From ecec1ff2a7e662e72df39837ea5bad4590f54734 Mon Sep 17 00:00:00 2001 From: TsFreddie Date: Wed, 28 Aug 2024 10:55:35 +0800 Subject: [PATCH 01/30] Resample to the device playback rate --- src/engine/client/sound.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/engine/client/sound.cpp b/src/engine/client/sound.cpp index 9c9881b12f6..6813cde9fa5 100644 --- a/src/engine/client/sound.cpp +++ b/src/engine/client/sound.cpp @@ -228,10 +228,8 @@ int CSound::Init() return -1; } - m_MixingRate = g_Config.m_SndRate; - SDL_AudioSpec Format, FormatOut; - Format.freq = m_MixingRate; + Format.freq = g_Config.m_SndRate; Format.format = AUDIO_S16; Format.channels = 2; Format.samples = g_Config.m_SndBufferSize; @@ -239,7 +237,7 @@ int CSound::Init() Format.userdata = this; // Open the audio device and start playing sound! - m_Device = SDL_OpenAudioDevice(nullptr, 0, &Format, &FormatOut, 0); + m_Device = SDL_OpenAudioDevice(nullptr, 0, &Format, &FormatOut, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE); if(m_Device == 0) { dbg_msg("sound", "unable to open audio: %s", SDL_GetError()); @@ -248,6 +246,7 @@ int CSound::Init() else dbg_msg("sound", "sound init successful using audio driver '%s'", SDL_GetCurrentAudioDriver()); + m_MixingRate = FormatOut.freq; m_MaxFrames = FormatOut.samples * 2; #if defined(CONF_VIDEORECORDER) m_MaxFrames = maximum(m_MaxFrames, 1024 * 2); // make the buffer bigger just in case From 43dee5d4c597f761549bb844a42026ea00aa491a Mon Sep 17 00:00:00 2001 From: ChillerDragon Date: Thu, 29 Aug 2024 15:15:48 +0800 Subject: [PATCH 02/30] Share gameflags for 0.6/0.7 instead of hardcoding it https://github.com/ddnet/ddnet/blob/5cf0e5e99788c0d883e4c7d18bed2ff6c5e6a424/datasrc/network.py#L8 https://github.com/ddnet/ddnet/blob/5cf0e5e99788c0d883e4c7d18bed2ff6c5e6a424/datasrc/seven/network.py#L10 0.6 game flags: ```python GameFlags = ["TEAMS", "FLAGS"] ``` 0.7 game flags: ```python GameFlags = Flags("GAMEFLAG", ["TEAMS", "FLAGS", "SURVIVAL", "RACE"]) ``` The 0.7 protocol extended the game flags without changing the old 0.6 flags. So flag teams and flag flags are the same in both versions and 0.7 just has additional flags. The server is now sending the same m_GameFlags from the gamemode controller to 0.6 and 0.7 connections. It clamps away the unsupported flags for 0.6. Before this commit the ddnet server would always send the hardcodet race flag to 0.7 connections while ignoring what the gamemode set as a game flag. --- src/engine/shared/protocolglue.cpp | 10 ++++++++++ src/engine/shared/protocolglue.h | 1 + src/game/server/gamecontext.cpp | 20 -------------------- src/game/server/gamecontroller.cpp | 23 ++++++++++++++++++++++- src/game/server/gamemodes/DDRace.cpp | 1 + 5 files changed, 34 insertions(+), 21 deletions(-) diff --git a/src/engine/shared/protocolglue.cpp b/src/engine/shared/protocolglue.cpp index e6bc23f95c7..e690614ca4c 100644 --- a/src/engine/shared/protocolglue.cpp +++ b/src/engine/shared/protocolglue.cpp @@ -4,6 +4,16 @@ #include "protocolglue.h" +int GameFlags_ClampToSix(int Flags) +{ + int Six = 0; + if(Flags & GAMEFLAG_TEAMS) + Six |= GAMEFLAG_TEAMS; + if(Flags & GAMEFLAG_FLAGS) + Six |= GAMEFLAG_FLAGS; + return Six; +} + int PlayerFlags_SevenToSix(int Flags) { int Six = 0; diff --git a/src/engine/shared/protocolglue.h b/src/engine/shared/protocolglue.h index 8fa2f13dd45..614cc629880 100644 --- a/src/engine/shared/protocolglue.h +++ b/src/engine/shared/protocolglue.h @@ -1,6 +1,7 @@ #ifndef ENGINE_SHARED_PROTOCOLGLUE_H #define ENGINE_SHARED_PROTOCOLGLUE_H +int GameFlags_ClampToSix(int Flags); int PlayerFlags_SevenToSix(int Flags); int PlayerFlags_SixToSeven(int Flags); void PickupType_SevenToSix(int Type7, int &Type6, int &SubType6); diff --git a/src/game/server/gamecontext.cpp b/src/game/server/gamecontext.cpp index 27cc8990d2a..61faa6a290b 100644 --- a/src/game/server/gamecontext.cpp +++ b/src/game/server/gamecontext.cpp @@ -1483,26 +1483,6 @@ void CGameContext::OnClientEnter(int ClientId) } m_pController->OnPlayerConnect(m_apPlayers[ClientId]); - if(Server()->IsSixup(ClientId)) - { - { - protocol7::CNetMsg_Sv_GameInfo Msg; - Msg.m_GameFlags = protocol7::GAMEFLAG_RACE; - Msg.m_MatchCurrent = 1; - Msg.m_MatchNum = 0; - Msg.m_ScoreLimit = 0; - Msg.m_TimeLimit = 0; - Server()->SendPackMsg(&Msg, MSGFLAG_VITAL | MSGFLAG_NORECORD, ClientId); - } - - // /team is essential - { - protocol7::CNetMsg_Sv_CommandInfoRemove Msg; - Msg.m_pName = "team"; - Server()->SendPackMsg(&Msg, MSGFLAG_VITAL | MSGFLAG_NORECORD, ClientId); - } - } - { CNetMsg_Sv_CommandInfoGroupStart Msg; Server()->SendPackMsg(&Msg, MSGFLAG_VITAL | MSGFLAG_NORECORD, ClientId); diff --git a/src/game/server/gamecontroller.cpp b/src/game/server/gamecontroller.cpp index 3ca74ba05a2..ab5be9dd597 100644 --- a/src/game/server/gamecontroller.cpp +++ b/src/game/server/gamecontroller.cpp @@ -2,6 +2,7 @@ /* If you are missing that file, acquire a complete release at teeworlds.com. */ #include +#include #include #include #include @@ -397,6 +398,26 @@ void IGameController::OnPlayerConnect(CPlayer *pPlayer) str_format(aBuf, sizeof(aBuf), "team_join player='%d:%s' team=%d", ClientId, Server()->ClientName(ClientId), pPlayer->GetTeam()); GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", aBuf); } + + if(Server()->IsSixup(ClientId)) + { + { + protocol7::CNetMsg_Sv_GameInfo Msg; + Msg.m_GameFlags = m_GameFlags; + Msg.m_MatchCurrent = 1; + Msg.m_MatchNum = 0; + Msg.m_ScoreLimit = 0; + Msg.m_TimeLimit = 0; + Server()->SendPackMsg(&Msg, MSGFLAG_VITAL | MSGFLAG_NORECORD, ClientId); + } + + // /team is essential + { + protocol7::CNetMsg_Sv_CommandInfoRemove Msg; + Msg.m_pName = "team"; + Server()->SendPackMsg(&Msg, MSGFLAG_VITAL | MSGFLAG_NORECORD, ClientId); + } + } } void IGameController::OnPlayerDisconnect(class CPlayer *pPlayer, const char *pReason) @@ -553,7 +574,7 @@ void IGameController::Snap(int SnappingClient) if(!pGameInfoObj) return; - pGameInfoObj->m_GameFlags = m_GameFlags; + pGameInfoObj->m_GameFlags = GameFlags_ClampToSix(m_GameFlags); pGameInfoObj->m_GameStateFlags = 0; if(m_GameOverTick != -1) pGameInfoObj->m_GameStateFlags |= GAMESTATEFLAG_GAMEOVER; diff --git a/src/game/server/gamemodes/DDRace.cpp b/src/game/server/gamemodes/DDRace.cpp index efbef3c520f..da14b863abd 100644 --- a/src/game/server/gamemodes/DDRace.cpp +++ b/src/game/server/gamemodes/DDRace.cpp @@ -18,6 +18,7 @@ CGameControllerDDRace::CGameControllerDDRace(class CGameContext *pGameServer) : IGameController(pGameServer) { m_pGameType = g_Config.m_SvTestingCommands ? TEST_TYPE_NAME : GAME_TYPE_NAME; + m_GameFlags = protocol7::GAMEFLAG_RACE; } CGameControllerDDRace::~CGameControllerDDRace() = default; From 1d65fff3ff9dc42069d829ec8da954f3c85336dd Mon Sep 17 00:00:00 2001 From: furo Date: Thu, 29 Aug 2024 12:46:11 +0200 Subject: [PATCH 03/30] Update Swedish translations for 18.5 --- data/languages/swedish.txt | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/data/languages/swedish.txt b/data/languages/swedish.txt index d6ea9d7221f..e66a87f2102 100644 --- a/data/languages/swedish.txt +++ b/data/languages/swedish.txt @@ -7,7 +7,7 @@ # 3edcxzaq1 2020-06-25 00:00:00 # cur.ie 2020-09-28 00:00:00 # simpygirl 2022-02-20 00:00:00 -# furo 2024-07-17 00:00:00 +# furo 2024-08-29 00:00:00 ##### /authors ##### ##### translated strings ##### @@ -1868,52 +1868,52 @@ https://wiki.ddnet.org/wiki/Mapping == https://wiki.ddnet.org/wiki/Mapping Could not resolve connect address '%s'. See local console for details. -== +== Kunde inte förstå anslutnings adress '%s'. Se den lokala konsolen för detaljer. Connect address error -== +== Anslutnings problem Could not connect dummy -== +== Kunde inte ansluta dummy Dummy is not allowed on this server -== +== Dummy är inte tillåten på denna server Please wait… -== +== Vänligen vänta… Show client IDs (scoreboard, chat, spectator) -== +== Visa klient IDen (poänglistan, chatt, åskadarmeny) Normal: -== +== Normal: Team: -== +== Lag: Dummy settings -== +== Dummy inställningar Toggle to edit your dummy settings -== +== Växla för att ändra dina dummy inställningar Randomize -== +== Slumpa Are you sure that you want to delete '%s'? -== +== Är du säker att du vill ta bort '%s'? Delete skin -== +== Ta bort skin Basic -== +== Enkel Custom -== +== Anpassa Unable to delete skin -== +== Kunde inte ta bort skin Customize -== +== Ändra From cdc5b9922a066bf2d456830549a4f52aa51ee1b8 Mon Sep 17 00:00:00 2001 From: Andrii <113429882+EGYT5453@users.noreply.github.com> Date: Fri, 30 Aug 2024 10:41:55 +0300 Subject: [PATCH 04/30] Update Ukrainian l10n (18.5) --- data/languages/ukrainian.txt | 102 +++++++++++++++++------------------ 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/data/languages/ukrainian.txt b/data/languages/ukrainian.txt index 0f6f69074de..8de03c1fb02 100644 --- a/data/languages/ukrainian.txt +++ b/data/languages/ukrainian.txt @@ -165,6 +165,9 @@ AntiPing: predict weapons Appearance == Вигляд +Are you sure that you want to delete '%s'? +== Ви дійсно хочете видалити '%s'? + Are you sure that you want to delete the demo '%s'? == Ви дійсно хочете видалити демо '%s'? @@ -237,6 +240,9 @@ Background Background music volume == Гучність фонової музики +Basic +== Базовий + Best == НКом @@ -330,6 +336,9 @@ Communities Config directory == Тека налаштувань +Connect address error +== Помилка адреси з'єднання + Connect Dummy == Приєднати даммі @@ -366,6 +375,9 @@ Converse Copy info == Скопіювати +Could not connect dummy +== Не вдалося під'єднати даммі + [Graphics error] Could not initialize the given graphics backend, reverting to the default backend now. == Не вдалося ініціалізувати заданий графічний рушій, повертаємося до рушія за замовчуванням. @@ -374,6 +386,9 @@ Could not initialize the given graphics backend, reverting to the default backen Could not initialize the given graphics backend, this is probably because you didn't install the driver of the integrated graphics card. == Не вдалося ініціалізувати заданий графічний рушій, можливо тому що ви не встановили драйвери на вбудовану відеокарту. +Could not resolve connect address '%s'. See local console for details. +== Не вдалося визначити адресу з'єднання '%s' (див. локальну консоль). + Could not save downloaded map. Try manually deleting this file: %s == Не вдалося зберегти завантажену мапу. Спробуйте самостійно видалити цей файл: %s @@ -395,9 +410,15 @@ Current custom == власний +Custom +== Власний + Custom colors == Власні кольори +Customize +== Налаштування + Cut interval == Інтервал @@ -458,6 +479,9 @@ Delete demo Delete folder == Видалити теку +Delete skin +== Видалити скін + Demo == Демо @@ -512,6 +536,12 @@ Dummy Dummy copy == Повторювати рухи +Dummy is not allowed on this server +== Використання даммі заборонене на цьому сервері + +Dummy settings +== Налаштування даммі + Dynamic Camera == Рухома камера @@ -1071,6 +1101,9 @@ No updates available None == Немає +Normal: +== Звичайний: + Normal Color == Колір звичайних повідомлень @@ -1188,6 +1221,9 @@ Please enter your nickname below. Please use a different filename == Будь ласка, назвіть файл по-іншому +Please wait… +== Будь ласка, зачекайте… + Position: == Позиція: @@ -1215,6 +1251,9 @@ Quitting. Please wait… Race == Забіг +Randomize +== Випадково + Ratio == У/С @@ -1411,6 +1450,9 @@ Show chat Show clan above name plates == Показувати клан над ніками +Show client IDs (scoreboard, chat, spectator) +== Показувати ID клієнта (табло, чат, спостерігачі) + Show DDNet map finishes in server browser == Показувати пройдені мапи DDNet у браузері серверів @@ -1631,6 +1673,9 @@ System message Team == Команда +Team: +== Командний: + Team %d == Команда %d @@ -1688,6 +1733,9 @@ Toggle ghost Toggle keyboard shortcuts == Перемкнути скорочення +Toggle to edit your dummy settings +== Перемкніть, щоб змінити налаштування даммі + transmits your player name to info.ddnet.org == передає ваш нікнейм до info.ddnet.org @@ -1724,6 +1772,9 @@ UI controller sens. UI mouse sens. == Чутл. у інтерфейсі +Unable to delete skin +== Не вдалося видалити скін + Unable to delete the demo '%s' == Не вдалося видалити демо '%s' @@ -1862,54 +1913,3 @@ Zoom in Zoom out == Віддалити - -Could not resolve connect address '%s'. See local console for details. -== - -Connect address error -== - -Could not connect dummy -== - -Dummy is not allowed on this server -== - -Please wait… -== - -Show client IDs (scoreboard, chat, spectator) -== - -Normal: -== - -Team: -== - -Dummy settings -== - -Toggle to edit your dummy settings -== - -Randomize -== - -Are you sure that you want to delete '%s'? -== - -Delete skin -== - -Basic -== - -Custom -== - -Unable to delete skin -== - -Customize -== From 05970178b285fa798d1905b792a3b9a4c8c33771 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Wed, 28 Aug 2024 23:04:53 +0200 Subject: [PATCH 05/30] Fix map downloading overriding more recent map change messages Following sequence of events was possible: 1. HTTP map download for map X is started (e.g. client initially connects to server). 2. Map change message for map Y arrives while downloading (e.g. vote for another map has passed on the server). 3. Client already has map Y and loads it directly without starting or resetting the map download. 4. HTTP map download task for map X finishes. 5. Map X is loaded, overriding the map Y that should be loaded. This is one cause for #2804. This could potentially also happen with the map download from the game-server, if the final map data chunk for a downloaded map is received directly after another map change message for a map which does not need to be downloaded, though this seems more unlikely. This is fixed by resetting the current map download immediately after receiving a valid map change message instead of only when starting a new map download. The relevant code to reset the map download is moved to `CClient::ResetMapDownload` to avoid duplicate code and ensure that the temporary map download file is always deleted and closed. --- src/engine/client/client.cpp | 74 ++++++++++++++---------------------- 1 file changed, 29 insertions(+), 45 deletions(-) diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index 06b399eae5b..f6aa93b71aa 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -247,11 +247,7 @@ void CClient::SendReady(int Conn) void CClient::SendMapRequest() { - if(m_MapdownloadFileTemp) - { - io_close(m_MapdownloadFileTemp); - Storage()->RemoveFile(m_aMapdownloadFilenameTemp, IStorage::TYPE_SAVE); - } + dbg_assert(!m_MapdownloadFileTemp, "Map download already in progress"); m_MapdownloadFileTemp = Storage()->OpenFile(m_aMapdownloadFilenameTemp, IOFLAG_WRITE, IStorage::TYPE_SAVE); if(IsSixup()) { @@ -656,6 +652,7 @@ void CClient::DisconnectWithReason(const char *pReason) m_aRconAuthed[0] = 0; mem_zero(m_aRconUsername, sizeof(m_aRconUsername)); mem_zero(m_aRconPassword, sizeof(m_aRconPassword)); + m_MapDetailsPresent = false; m_ServerSentCapabilities = false; m_UseTempRconCommands = 0; m_ExpectedRconCommands = -1; @@ -671,22 +668,10 @@ void CClient::DisconnectWithReason(const char *pReason) m_CurrentServerCurrentPingTime = -1; m_CurrentServerNextPingTime = -1; - // disable all downloads - m_MapdownloadChunk = 0; - if(m_pMapdownloadTask) - m_pMapdownloadTask->Abort(); - if(m_MapdownloadFileTemp) - { - io_close(m_MapdownloadFileTemp); - Storage()->RemoveFile(m_aMapdownloadFilenameTemp, IStorage::TYPE_SAVE); - } - m_MapdownloadFileTemp = 0; - m_MapdownloadSha256Present = false; - m_MapdownloadSha256 = SHA256_ZEROED; - m_MapdownloadCrc = 0; - m_MapdownloadTotalsize = -1; - m_MapdownloadAmount = 0; - m_MapDetailsPresent = false; + ResetMapDownload(); + m_aMapdownloadFilename[0] = '\0'; + m_aMapdownloadFilenameTemp[0] = '\0'; + m_aMapdownloadName[0] = '\0'; // clear the current server info mem_zero(&m_CurrentServerInfo, sizeof(m_CurrentServerInfo)); @@ -1543,6 +1528,8 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket, int Conn, bool Dummy) DummyDisconnect(0); } + ResetMapDownload(); + SHA256_DIGEST *pMapSha256 = nullptr; const char *pMapUrl = nullptr; if(MapDetailsWerePresent && str_comp(m_aMapDetailsName, pMap) == 0 && m_MapDetailsCrc == MapCrc) @@ -1559,12 +1546,6 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket, int Conn, bool Dummy) } else { - if(m_MapdownloadFileTemp) - { - io_close(m_MapdownloadFileTemp); - Storage()->RemoveFile(m_aMapdownloadFilenameTemp, IStorage::TYPE_SAVE); - } - // start map download FormatMapDownloadFilename(pMap, pMapSha256, MapCrc, false, m_aMapdownloadFilename, sizeof(m_aMapdownloadFilename)); FormatMapDownloadFilename(pMap, pMapSha256, MapCrc, true, m_aMapdownloadFilenameTemp, sizeof(m_aMapdownloadFilenameTemp)); @@ -1573,16 +1554,11 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket, int Conn, bool Dummy) str_format(aBuf, sizeof(aBuf), "starting to download map to '%s'", m_aMapdownloadFilenameTemp); m_pConsole->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "client/network", aBuf); - m_MapdownloadChunk = 0; str_copy(m_aMapdownloadName, pMap); - m_MapdownloadSha256Present = (bool)pMapSha256; m_MapdownloadSha256 = pMapSha256 ? *pMapSha256 : SHA256_ZEROED; m_MapdownloadCrc = MapCrc; m_MapdownloadTotalsize = MapSize; - m_MapdownloadAmount = 0; - - ResetMapDownload(); if(pMapSha256) { @@ -2225,9 +2201,25 @@ void CClient::ResetMapDownload() if(m_pMapdownloadTask) { m_pMapdownloadTask->Abort(); - m_pMapdownloadTask = NULL; + m_pMapdownloadTask = nullptr; + } + + if(m_MapdownloadFileTemp) + { + io_close(m_MapdownloadFileTemp); + m_MapdownloadFileTemp = 0; + } + + if(Storage()->FileExists(m_aMapdownloadFilenameTemp, IStorage::TYPE_SAVE)) + { + Storage()->RemoveFile(m_aMapdownloadFilenameTemp, IStorage::TYPE_SAVE); } - m_MapdownloadFileTemp = 0; + + m_MapdownloadChunk = 0; + m_MapdownloadSha256Present = false; + m_MapdownloadSha256 = SHA256_ZEROED; + m_MapdownloadCrc = 0; + m_MapdownloadTotalsize = -1; m_MapdownloadAmount = 0; } @@ -2235,9 +2227,8 @@ void CClient::FinishMapDownload() { m_pConsole->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "client/network", "download complete, loading map"); - int Prev = m_MapdownloadTotalsize; - m_MapdownloadTotalsize = -1; - SHA256_DIGEST *pSha256 = m_MapdownloadSha256Present ? &m_MapdownloadSha256 : 0; + const int PrevMapdownloadTotalsize = m_MapdownloadTotalsize; + SHA256_DIGEST *pSha256 = m_MapdownloadSha256Present ? &m_MapdownloadSha256 : nullptr; bool FileSuccess = true; if(Storage()->FileExists(m_aMapdownloadFilename, IStorage::TYPE_SAVE)) @@ -2252,7 +2243,6 @@ void CClient::FinishMapDownload() return; } - // load map const char *pError = LoadMap(m_aMapdownloadName, m_aMapdownloadFilename, pSha256, m_MapdownloadCrc); if(!pError) { @@ -2263,17 +2253,11 @@ void CClient::FinishMapDownload() else if(m_pMapdownloadTask) // fallback { ResetMapDownload(); - m_MapdownloadTotalsize = Prev; + m_MapdownloadTotalsize = PrevMapdownloadTotalsize; SendMapRequest(); } else { - if(m_MapdownloadFileTemp) - { - io_close(m_MapdownloadFileTemp); - m_MapdownloadFileTemp = 0; - Storage()->RemoveFile(m_aMapdownloadFilenameTemp, IStorage::TYPE_SAVE); - } ResetMapDownload(); DisconnectWithReason(pError); } From d40cc86bfa74b0198018fb1bf09f61ded93bcbbd Mon Sep 17 00:00:00 2001 From: furo Date: Fri, 30 Aug 2024 20:15:26 +0200 Subject: [PATCH 06/30] Set correct end line in `twlang.py` for strings with context --- scripts/languages/twlang.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/languages/twlang.py b/scripts/languages/twlang.py index eba1c911610..28b3fe1d5ac 100644 --- a/scripts/languages/twlang.py +++ b/scripts/languages/twlang.py @@ -37,7 +37,7 @@ def decode(fileobj, elements_per_key): if current_key: if len(data[current_key]) != 1+elements_per_key: raise LanguageDecodeError("Wrong number of elements per key", fileobj.name, index) - data[current_key].append(index) + data[current_key].append(index - 1 if current_context else index) if line in data: raise LanguageDecodeError("Key defined multiple times: " + line, fileobj.name, index) data[(line, current_context)] = [index - 1 if current_context else index] From c10b466a40bec7f89626fe73e9f42059c614bcee Mon Sep 17 00:00:00 2001 From: dobrykafe Date: Fri, 30 Aug 2024 22:18:35 +0200 Subject: [PATCH 07/30] update czech translations for 18.5 --- data/languages/czech.txt | 50 ++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/data/languages/czech.txt b/data/languages/czech.txt index 7ca70d42473..d97119fb13e 100644 --- a/data/languages/czech.txt +++ b/data/languages/czech.txt @@ -6,7 +6,7 @@ # Petr 2011-04-02 23:02:33 # Medik & Petr 2011-07-02 19:37:05 # TeeWorlds-org 2011-07-15 00:34:19 -# dobrykafe 2024-06-09 00:00:00 +# dobrykafe 2024-08-30 00:00:00 ##### /authors ##### ##### translated strings ##### @@ -1845,76 +1845,76 @@ Show only chat messages from team members == Zobrazit pouze zprávy od členů týmu Could not resolve connect address '%s'. See local console for details. -== +== Nelze získat adresu k připojení '%s'. Podrobnosti najdete v místní konzoli. Connect address error -== +== Chyba v adrese k připojení Could not connect dummy -== +== Nepodařilo se připojit dummyho [Spectating] Following %s -== +== Sledujete %s Example of usage -== +== Příklad použití Dummy is not allowed on this server -== +== Dummy není na tomto serveru povolen Please wait… -== +== Čekejte prosím… Show client IDs (scoreboard, chat, spectator) -== +== Zobrazit ID klientů (výsledková tabulka, chat, divák) Normal: -== +== Normální: Team: -== +== Tým: Dummy settings -== +== Nastavení dummyho Toggle to edit your dummy settings -== +== Přepnutím upravíte nastavení dummyho Randomize -== +== Randomizovat Are you sure that you want to delete '%s'? -== +== Jste si jisti, že chcete smazat '%s'? Delete skin -== +== Odstranit skin Basic -== +== Základní Custom -== +== Vlastní Unable to delete skin -== +== Nelze odstranit skin Customize -== +== Přizpůsobit Round %d/%d -== +== Kolo %d/%d [Spectators] %d others… -== +== %d dalších… [Team and size] %d\n(%d/%d) -== +== %d\n(%d/%d) Team %d (%d/%d) -== +== Tým %d (%d/%d) https://wiki.ddnet.org/wiki/Mapping -== +== https://wiki.ddnet.org/wiki/Mapping From 29a205a6d938473211796863ad210d0484467c31 Mon Sep 17 00:00:00 2001 From: dobrykafe Date: Fri, 30 Aug 2024 22:18:45 +0200 Subject: [PATCH 08/30] update slovak translations for 18.5 --- data/languages/slovak.txt | 50 +++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/data/languages/slovak.txt b/data/languages/slovak.txt index 6c2daa13c48..890e8a884a8 100644 --- a/data/languages/slovak.txt +++ b/data/languages/slovak.txt @@ -3,7 +3,7 @@ # Limit and Petr #modified by: # LimiT 2011-07-02 20:24:44 -# dobrykafe 2024-06-09 00:00:00 +# dobrykafe 2024-08-30 00:00:00 ##### /authors ##### ##### translated strings ##### @@ -1842,76 +1842,76 @@ Show only chat messages from team members == Zobraziť iba správy od členov tímu Could not resolve connect address '%s'. See local console for details. -== +== Nie je možné získať adresu na pripojenie '%s'. Podrobnosti nájdete v miestnej konzole. Connect address error -== +== Chyba v adrese na pripojenie Could not connect dummy -== +== Nepodarilo sa pripojiť dummyho [Spectating] Following %s -== +== Sledujete %s Example of usage -== +== Príklad použitia Dummy is not allowed on this server -== +== Dummy nie je na tomto serveri povolený Please wait… -== +== Čakajte prosím… Show client IDs (scoreboard, chat, spectator) -== +== Zobraziť ID klientov (výsledková tabuľka, chat, divák) Normal: -== +== Normálny: Team: -== +== Tím: Dummy settings -== +== Nastavenie dummyho Toggle to edit your dummy settings -== +== Prepnutím upravíte nastavenie dummyho Randomize -== +== Randomizovať Are you sure that you want to delete '%s'? -== +== Ste si istí, že chcete zmazať '%s'? Delete skin -== +== Odstrániť skin Basic -== +== Základné Custom -== +== Vlastné Unable to delete skin -== +== Nedá sa odstrániť skin Customize -== +== Prispôsobiť Round %d/%d -== +== Kolo %d/%d [Spectators] %d others… -== +== %d ďalších… [Team and size] %d\n(%d/%d) -== +== %d\n(%d/%d) Team %d (%d/%d) -== +== Tím %d (%d/%d) https://wiki.ddnet.org/wiki/Mapping -== +== https://wiki.ddnet.org/wiki/Mapping From d452bcda8fce9ce294a92bb61b94192f585a3460 Mon Sep 17 00:00:00 2001 From: KebsCS Date: Tue, 27 Aug 2024 22:47:24 +0200 Subject: [PATCH 09/30] Add validation for chat and console command arguments --- src/engine/console.h | 2 +- src/engine/shared/config.cpp | 25 +++++++----- src/engine/shared/console.cpp | 70 ++++++++++++++++++++++++--------- src/engine/shared/console.h | 13 +++++- src/rust-bridge/cpp/console.cpp | 4 +- 5 files changed, 81 insertions(+), 33 deletions(-) diff --git a/src/engine/console.h b/src/engine/console.h index 0c04678ebd1..ce79012d8e4 100644 --- a/src/engine/console.h +++ b/src/engine/console.h @@ -53,7 +53,7 @@ class IConsole : public IInterface virtual int GetInteger(unsigned Index) const = 0; virtual float GetFloat(unsigned Index) const = 0; virtual const char *GetString(unsigned Index) const = 0; - virtual ColorHSLA GetColor(unsigned Index, bool Light) const = 0; + virtual std::optional GetColor(unsigned Index, bool Light) const = 0; virtual void RemoveArgument(unsigned Index) = 0; diff --git a/src/engine/shared/config.cpp b/src/engine/shared/config.cpp index 1d78696e303..6c71c4b1152 100644 --- a/src/engine/shared/config.cpp +++ b/src/engine/shared/config.cpp @@ -111,22 +111,29 @@ void SIntConfigVariable::ResetToOld() void SColorConfigVariable::CommandCallback(IConsole::IResult *pResult, void *pUserData) { SColorConfigVariable *pData = static_cast(pUserData); - + char aBuf[IConsole::CMDLINE_LENGTH + 64]; if(pResult->NumArguments()) { if(pData->CheckReadOnly()) return; - const ColorHSLA Color = pResult->GetColor(0, pData->m_Light); - const unsigned Value = Color.Pack(pData->m_Light ? 0.5f : 0.0f, pData->m_Alpha); + const auto Color = pResult->GetColor(0, pData->m_Light); + if(Color) + { + const unsigned Value = Color->Pack(pData->m_Light ? 0.5f : 0.0f, pData->m_Alpha); - *pData->m_pVariable = Value; - if(pResult->m_ClientId != IConsole::CLIENT_ID_GAME) - pData->m_OldValue = Value; + *pData->m_pVariable = Value; + if(pResult->m_ClientId != IConsole::CLIENT_ID_GAME) + pData->m_OldValue = Value; + } + else + { + str_format(aBuf, sizeof(aBuf), "%s is not a valid color.", pResult->GetString(0)); + pData->m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "config", aBuf); + } } else { - char aBuf[256]; str_format(aBuf, sizeof(aBuf), "Value: %u", *pData->m_pVariable); pData->m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "config", aBuf); @@ -493,8 +500,8 @@ void CConfigManager::Con_Toggle(IConsole::IResult *pResult, void *pUserData) { SColorConfigVariable *pColorVariable = static_cast(pVariable); const float Darkest = pColorVariable->m_Light ? 0.5f : 0.0f; - const ColorHSLA Value = *pColorVariable->m_pVariable == pResult->GetColor(1, pColorVariable->m_Light).Pack(Darkest, pColorVariable->m_Alpha) ? pResult->GetColor(2, pColorVariable->m_Light) : pResult->GetColor(1, pColorVariable->m_Light); - pColorVariable->SetValue(Value.Pack(Darkest, pColorVariable->m_Alpha)); + const std::optional Value = *pColorVariable->m_pVariable == pResult->GetColor(1, pColorVariable->m_Light).value_or(ColorHSLA(0, 0, 0)).Pack(Darkest, pColorVariable->m_Alpha) ? pResult->GetColor(2, pColorVariable->m_Light) : pResult->GetColor(1, pColorVariable->m_Light); + pColorVariable->SetValue(Value.value_or(ColorHSLA(0, 0, 0)).Pack(Darkest, pColorVariable->m_Alpha)); } else if(pVariable->m_Type == SConfigVariable::VAR_STRING) { diff --git a/src/engine/shared/console.cpp b/src/engine/shared/console.cpp index 29610d79631..7c8a84ad6cd 100644 --- a/src/engine/shared/console.cpp +++ b/src/engine/shared/console.cpp @@ -40,22 +40,29 @@ float CConsole::CResult::GetFloat(unsigned Index) const return str_tofloat(m_apArgs[Index]); } -ColorHSLA CConsole::CResult::GetColor(unsigned Index, bool Light) const +std::optional CConsole::CResult::GetColor(unsigned Index, bool Light) const { if(Index >= m_NumArgs) - return ColorHSLA(0, 0, 0); + return std::nullopt; const char *pStr = m_apArgs[Index]; if(str_isallnum(pStr) || ((pStr[0] == '-' || pStr[0] == '+') && str_isallnum(pStr + 1))) // Teeworlds Color (Packed HSL) { - const ColorHSLA Hsla = ColorHSLA(str_toulong_base(pStr, 10), true); + unsigned long Value = str_toulong_base(pStr, 10); + if(Value == std::numeric_limits::max()) + return std::nullopt; + const ColorHSLA Hsla = ColorHSLA(Value, true); if(Light) return Hsla.UnclampLighting(); return Hsla; } else if(*pStr == '$') // Hex RGB/RGBA { - return color_cast(color_parse(pStr + 1).value_or(ColorRGBA(0.0f, 0.0f, 0.0f, 1.0f))); + auto ParsedColor = color_parse(pStr + 1); + if(ParsedColor) + return color_cast(ParsedColor.value()); + else + return std::nullopt; } else if(!str_comp_nocase(pStr, "red")) return ColorHSLA(0.0f / 6.0f, 1, .5f); @@ -76,7 +83,7 @@ ColorHSLA CConsole::CResult::GetColor(unsigned Index, bool Light) const else if(!str_comp_nocase(pStr, "black")) return ColorHSLA(0, 0, 0); - return ColorHSLA(0, 0, 0); + return std::nullopt; } const IConsole::CCommandInfo *CConsole::CCommand::NextCommandInfo(int AccessLevel, int FlagMask) const @@ -129,12 +136,12 @@ int CConsole::ParseStart(CResult *pResult, const char *pString, int Length) return 0; } -int CConsole::ParseArgs(CResult *pResult, const char *pFormat) +int CConsole::ParseArgs(CResult *pResult, const char *pFormat, FCommandCallback pfnCallback) { char Command = *pFormat; char *pStr; int Optional = 0; - int Error = 0; + int Error = PARSEARGS_OK; pResult->ResetVictim(); @@ -155,7 +162,7 @@ int CConsole::ParseArgs(CResult *pResult, const char *pFormat) { if(!Optional) { - Error = 1; + Error = PARSEARGS_MISSING_VALUE; break; } @@ -191,7 +198,7 @@ int CConsole::ParseArgs(CResult *pResult, const char *pFormat) pStr++; // skip due to escape } else if(pStr[0] == 0) - return 1; // return error + return PARSEARGS_MISSING_VALUE; // return error *pDst = *pStr; pDst++; @@ -215,13 +222,7 @@ int CConsole::ParseArgs(CResult *pResult, const char *pFormat) if(Command == 'r') // rest of the string break; - else if(Command == 'v') // validate victim - pStr = str_skip_to_whitespace(pStr); - else if(Command == 'i') // validate int - pStr = str_skip_to_whitespace(pStr); - else if(Command == 'f') // validate float - pStr = str_skip_to_whitespace(pStr); - else if(Command == 's') // validate string + else if(Command == 'v' || Command == 'i' || Command == 'f' || Command == 's') pStr = str_skip_to_whitespace(pStr); if(pStr[0] != 0) // check for end of string @@ -230,6 +231,32 @@ int CConsole::ParseArgs(CResult *pResult, const char *pFormat) pStr++; } + // validate args + if(Command == 'i') + { + // don't validate colors here + if(pfnCallback != &SColorConfigVariable::CommandCallback) + { + int Value; + if(!str_toint(pResult->GetString(pResult->NumArguments() - 1), &Value) || + Value == std::numeric_limits::max() || Value == std::numeric_limits::min()) + { + Error = PARSEARGS_INVALID_INTEGER; + break; + } + } + } + else if(Command == 'f') + { + float Value; + if(!str_tofloat(pResult->GetString(pResult->NumArguments() - 1), &Value) || + Value == std::numeric_limits::max() || Value == std::numeric_limits::min()) + { + Error = PARSEARGS_INVALID_FLOAT; + break; + } + } + if(pVictim) { pResult->SetVictim(pVictim); @@ -487,10 +514,15 @@ void CConsole::ExecuteLineStroked(int Stroke, const char *pStr, int ClientId, bo if(Stroke || IsStrokeCommand) { - if(ParseArgs(&Result, pCommand->m_pParams)) + if(int Error = ParseArgs(&Result, pCommand->m_pParams, pCommand->m_pfnCallback)) { - char aBuf[TEMPCMD_NAME_LENGTH + TEMPCMD_PARAMS_LENGTH + 32]; - str_format(aBuf, sizeof(aBuf), "Invalid arguments. Usage: %s %s", pCommand->m_pName, pCommand->m_pParams); + char aBuf[CMDLINE_LENGTH + 64]; + if(Error == PARSEARGS_INVALID_INTEGER) + str_format(aBuf, sizeof(aBuf), "%s is not a valid integer.", Result.GetString(Result.NumArguments() - 1)); + else if(Error == PARSEARGS_INVALID_FLOAT) + str_format(aBuf, sizeof(aBuf), "%s is not a valid decimal number.", Result.GetString(Result.NumArguments() - 1)); + else + str_format(aBuf, sizeof(aBuf), "Invalid arguments. Usage: %s %s", pCommand->m_pName, pCommand->m_pParams); Print(OUTPUT_LEVEL_STANDARD, "chatresp", aBuf); } else if(m_StoreCommands && pCommand->m_Flags & CFGFLAG_STORE) diff --git a/src/engine/shared/console.h b/src/engine/shared/console.h index 8d8a85231f8..c3779c6a2be 100644 --- a/src/engine/shared/console.h +++ b/src/engine/shared/console.h @@ -115,7 +115,7 @@ class CConsole : public IConsole const char *GetString(unsigned Index) const override; int GetInteger(unsigned Index) const override; float GetFloat(unsigned Index) const override; - ColorHSLA GetColor(unsigned Index, bool Light) const override; + std::optional GetColor(unsigned Index, bool Light) const override; void RemoveArgument(unsigned Index) override { @@ -144,7 +144,16 @@ class CConsole : public IConsole }; int ParseStart(CResult *pResult, const char *pString, int Length); - int ParseArgs(CResult *pResult, const char *pFormat); + + enum + { + PARSEARGS_OK = 0, + PARSEARGS_MISSING_VALUE, + PARSEARGS_INVALID_INTEGER, + PARSEARGS_INVALID_FLOAT, + }; + + int ParseArgs(CResult *pResult, const char *pFormat, FCommandCallback pfnCallback = 0); /* this function will set pFormat to the next parameter (i,s,r,v,?) it contains and diff --git a/src/rust-bridge/cpp/console.cpp b/src/rust-bridge/cpp/console.cpp index fb5e3cbd961..eeaab723bf6 100644 --- a/src/rust-bridge/cpp/console.cpp +++ b/src/rust-bridge/cpp/console.cpp @@ -109,8 +109,8 @@ void cxxbridge1$IConsole_IResult$GetString(const ::IConsole_IResult &self, ::std } void cxxbridge1$IConsole_IResult$GetColor(const ::IConsole_IResult &self, ::std::uint32_t Index, bool Light, ::ColorHSLA *return$) noexcept { - ::ColorHSLA (::IConsole_IResult::*GetColor$)(::std::uint32_t, bool) const = &::IConsole_IResult::GetColor; - new (return$) ::ColorHSLA((self.*GetColor$)(Index, Light)); + std::optional<::ColorHSLA> (::IConsole_IResult::*GetColor$)(::std::uint32_t, bool) const = &::IConsole_IResult::GetColor; + new(return$)::ColorHSLA((self.*GetColor$)(Index, Light).value_or(::ColorHSLA(0, 0, 0))); } ::std::int32_t cxxbridge1$IConsole_IResult$NumArguments(const ::IConsole_IResult &self) noexcept { From c02a2ed1d6e472829c0304ae7d27e9405ccba431 Mon Sep 17 00:00:00 2001 From: ChillerDragon Date: Sat, 31 Aug 2024 10:40:55 +0800 Subject: [PATCH 10/30] Simplify character tuning code entities/character.cpp now has the same api as prediction/entities/character.cpp --- src/game/server/entities/character.cpp | 56 +++++--------------------- src/game/server/entities/character.h | 1 + 2 files changed, 12 insertions(+), 45 deletions(-) diff --git a/src/game/server/entities/character.cpp b/src/game/server/entities/character.cpp index ab30766bcea..59f078297ce 100644 --- a/src/game/server/entities/character.cpp +++ b/src/game/server/entities/character.cpp @@ -234,11 +234,7 @@ void CCharacter::HandleJetpack() { if(m_Core.m_Jetpack) { - float Strength; - if(!m_TuneZone) - Strength = Tuning()->m_JetpackStrength; - else - Strength = TuningList()[m_TuneZone].m_JetpackStrength; + float Strength = GetTuning(m_TuneZone)->m_JetpackStrength; TakeDamage(Direction * -1.0f * (Strength / 100.0f / 6.11f), 0, m_pPlayer->GetCid(), m_Core.m_ActiveWeapon); } } @@ -282,12 +278,9 @@ void CCharacter::HandleNinja() // Set velocity m_Core.m_Vel = m_Core.m_Ninja.m_ActivationDir * g_pData->m_Weapons.m_Ninja.m_Velocity; vec2 OldPos = m_Pos; - vec2 GroundElasticity; - - if(!m_TuneZone) - GroundElasticity = vec2(Tuning()->m_GroundElasticityX, Tuning()->m_GroundElasticityY); - else - GroundElasticity = vec2(TuningList()[m_TuneZone].m_GroundElasticityX, TuningList()[m_TuneZone].m_GroundElasticityY); + vec2 GroundElasticity = vec2( + GetTuning(m_TuneZone)->m_GroundElasticityX, + GetTuning(m_TuneZone)->m_GroundElasticityY); Collision()->MoveBox(&m_Core.m_Pos, &m_Core.m_Vel, vec2(GetProximityRadius(), GetProximityRadius()), GroundElasticity); @@ -498,11 +491,7 @@ void CCharacter::FireWeapon() else Dir = vec2(0.f, -1.f); - float Strength; - if(!m_TuneZone) - Strength = Tuning()->m_HammerStrength; - else - Strength = TuningList()[m_TuneZone].m_HammerStrength; + float Strength = GetTuning(m_TuneZone)->m_HammerStrength; vec2 Temp = pTarget->m_Core.m_Vel + normalize(Dir + vec2(0.f, -1.1f)) * 10.0f; Temp = ClampVel(pTarget->m_MoveRestrictions, Temp); @@ -522,11 +511,7 @@ void CCharacter::FireWeapon() // if we Hit anything, we have to wait for the reload if(Hits) { - float FireDelay; - if(!m_TuneZone) - FireDelay = Tuning()->m_HammerHitFireDelay; - else - FireDelay = TuningList()[m_TuneZone].m_HammerHitFireDelay; + float FireDelay = GetTuning(m_TuneZone)->m_HammerHitFireDelay; m_ReloadTimer = FireDelay * Server()->TickSpeed() / 1000; } } @@ -536,11 +521,7 @@ void CCharacter::FireWeapon() { if(!m_Core.m_Jetpack || !m_pPlayer->m_NinjaJetpack || m_Core.m_HasTelegunGun) { - int Lifetime; - if(!m_TuneZone) - Lifetime = (int)(Server()->TickSpeed() * Tuning()->m_GunLifetime); - else - Lifetime = (int)(Server()->TickSpeed() * TuningList()[m_TuneZone].m_GunLifetime); + int Lifetime = (int)(Server()->TickSpeed() * GetTuning(m_TuneZone)->m_GunLifetime); new CProjectile( GameWorld(), @@ -562,11 +543,7 @@ void CCharacter::FireWeapon() case WEAPON_SHOTGUN: { - float LaserReach; - if(!m_TuneZone) - LaserReach = Tuning()->m_LaserReach; - else - LaserReach = TuningList()[m_TuneZone].m_LaserReach; + float LaserReach = GetTuning(m_TuneZone)->m_LaserReach; new CLaser(&GameServer()->m_World, m_Pos, Direction, LaserReach, m_pPlayer->GetCid(), WEAPON_SHOTGUN); GameServer()->CreateSound(m_Pos, SOUND_SHOTGUN_FIRE, TeamMask()); // NOLINT(clang-analyzer-unix.Malloc) @@ -575,11 +552,7 @@ void CCharacter::FireWeapon() case WEAPON_GRENADE: { - int Lifetime; - if(!m_TuneZone) - Lifetime = (int)(Server()->TickSpeed() * Tuning()->m_GrenadeLifetime); - else - Lifetime = (int)(Server()->TickSpeed() * TuningList()[m_TuneZone].m_GrenadeLifetime); + int Lifetime = (int)(Server()->TickSpeed() * GetTuning(m_TuneZone)->m_GrenadeLifetime); new CProjectile( GameWorld(), @@ -600,11 +573,7 @@ void CCharacter::FireWeapon() case WEAPON_LASER: { - float LaserReach; - if(!m_TuneZone) - LaserReach = Tuning()->m_LaserReach; - else - LaserReach = TuningList()[m_TuneZone].m_LaserReach; + float LaserReach = GetTuning(m_TuneZone)->m_LaserReach; new CLaser(GameWorld(), m_Pos, Direction, LaserReach, m_pPlayer->GetCid(), WEAPON_LASER); GameServer()->CreateSound(m_Pos, SOUND_LASER_FIRE, TeamMask()); // NOLINT(clang-analyzer-unix.Malloc) @@ -630,10 +599,7 @@ void CCharacter::FireWeapon() if(!m_ReloadTimer) { float FireDelay; - if(!m_TuneZone) - Tuning()->Get(38 + m_Core.m_ActiveWeapon, &FireDelay); - else - TuningList()[m_TuneZone].Get(38 + m_Core.m_ActiveWeapon, &FireDelay); + GetTuning(m_TuneZone)->Get(38 + m_Core.m_ActiveWeapon, &FireDelay); m_ReloadTimer = FireDelay * Server()->TickSpeed() / 1000; } } diff --git a/src/game/server/entities/character.h b/src/game/server/entities/character.h index 54651f41020..df569dc2c69 100644 --- a/src/game/server/entities/character.h +++ b/src/game/server/entities/character.h @@ -263,6 +263,7 @@ class CCharacter : public CEntity bool IsSuper() const { return m_Core.m_Super; } CSaveTee &GetLastRescueTeeRef(int Mode = RESCUEMODE_AUTO) { return m_RescueTee[Mode]; } + CTuningParams *GetTuning(int Zone) { return Zone ? &TuningList()[Zone] : Tuning(); } }; enum From 383bef93b9644b6412ea9b7df88fb7e5b310b33b Mon Sep 17 00:00:00 2001 From: JuraIBOZO <142632373+JuraIBOZO@users.noreply.github.com> Date: Sat, 31 Aug 2024 11:03:44 +0300 Subject: [PATCH 11/30] Update russian.txt --- data/languages/russian.txt | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/data/languages/russian.txt b/data/languages/russian.txt index e0148292dad..896b15e92d7 100644 --- a/data/languages/russian.txt +++ b/data/languages/russian.txt @@ -1880,52 +1880,52 @@ https://wiki.ddnet.org/wiki/Mapping == https://wiki.ddnet.org/wiki/Mapping/ru Could not resolve connect address '%s'. See local console for details. -== +== Не удалось определить адрес подключения '%s'. Подробности в локальной консоли. Connect address error -== +== Ошибка подключения сервера Could not connect dummy -== +== Невозможно подключить дамми Dummy is not allowed on this server -== +== Дамми не разрешен на этом сервере Please wait… -== +== Пожалуйста подождите… Show client IDs (scoreboard, chat, spectator) -== +== Показывать ID клиента (Табло, чат, наблюдатель) Normal: -== +== Обычный: Team: -== +== Команда: Dummy settings -== +== Настройки дамми Toggle to edit your dummy settings -== +== Нажмите чтоб изменить настройки дамми Randomize -== +== Перемешать Are you sure that you want to delete '%s'? -== +== Вы уверены что хотите удалить '%s'? Delete skin -== +== Удалить скин Basic -== +== Базовый Custom -== +== Кастомизация Unable to delete skin -== +== Невозможно удалить скин Customize -== +== Кастомизировать From 468900acfe8255514bebba2397628283b2891cf5 Mon Sep 17 00:00:00 2001 From: Vlad Date: Sat, 31 Aug 2024 13:44:09 +0300 Subject: [PATCH 12/30] typos in russian.txt --- data/languages/russian.txt | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/data/languages/russian.txt b/data/languages/russian.txt index 896b15e92d7..5f2a9f2cd95 100644 --- a/data/languages/russian.txt +++ b/data/languages/russian.txt @@ -631,7 +631,7 @@ Loading DDNet Client == Загрузка DDNet Client Normal message -== Обычное с. +== Обычное Connecting dummy == Подключение дамми @@ -643,10 +643,10 @@ Save ghost == Сохранять тень DDNet Client updated! -== DDNet Client обновлён! +== DDNet клиент обновлён! Highlighted message -== Выделенное с. +== Выделенное Demo == Демо @@ -724,7 +724,7 @@ Downloading %s: == Скачивание %s: Update failed! Check log… -== Ошибка. Проверьте логи… +== Не удалось обновиться! Подробности в логах… Restart == Рестарт @@ -844,7 +844,7 @@ DDNet == DDNet Friend message -== Дружеское с. +== Дружеское Save the best demo of each race == Сохранять лучшее демо каждой карты @@ -916,10 +916,10 @@ Ratio == Соотношение Net -== Сеть +== Сальдо FPM -== FPM +== У/мин Spree == Серия @@ -940,7 +940,7 @@ Grabs == 9+ упоминаний Client message -== Клиентское с. +== Клиентское Warning == Предупреждение @@ -973,7 +973,7 @@ Run server == Запустить сервер Server executable not found, can't run server -== Файл сервера не найден, невозможно запустить +== Файл сервера не найден, не удалось запустить сервер Editor == Редактор @@ -1883,7 +1883,7 @@ Could not resolve connect address '%s'. See local console for details. == Не удалось определить адрес подключения '%s'. Подробности в локальной консоли. Connect address error -== Ошибка подключения сервера +== Ошибка адреса подключения Could not connect dummy == Невозможно подключить дамми @@ -1892,34 +1892,34 @@ Dummy is not allowed on this server == Дамми не разрешен на этом сервере Please wait… -== Пожалуйста подождите… +== Пожалуйста, подождите… Show client IDs (scoreboard, chat, spectator) -== Показывать ID клиента (Табло, чат, наблюдатель) +== Показывать ID клиента (табло, чат, наблюдатель) Normal: == Обычный: Team: -== Команда: +== В команде: Dummy settings == Настройки дамми Toggle to edit your dummy settings -== Нажмите чтоб изменить настройки дамми +== Нажмите, чтобы изменить настройки дамми Randomize -== Перемешать +== Случайный Are you sure that you want to delete '%s'? -== Вы уверены что хотите удалить '%s'? +== Вы уверены, что хотите удалить '%s'? Delete skin == Удалить скин Basic -== Базовый +== Пресеты Custom == Кастомизация From bb45db8ad3becce027708be7b866f67ef21e29c3 Mon Sep 17 00:00:00 2001 From: veydzh3r <108631328+Veydzher@users.noreply.github.com> Date: Sat, 31 Aug 2024 11:51:57 +0100 Subject: [PATCH 13/30] Update ukrainian.txt --- data/languages/ukrainian.txt | 257 ++++++++++++++++++----------------- 1 file changed, 129 insertions(+), 128 deletions(-) diff --git a/data/languages/ukrainian.txt b/data/languages/ukrainian.txt index 8de03c1fb02..eaf5b1b4342 100644 --- a/data/languages/ukrainian.txt +++ b/data/languages/ukrainian.txt @@ -4,6 +4,7 @@ #modified by: # 404_not_found 2011-07-30 19:50:58 # EGYT5453 (15.05.2024-04.06.2024) +# veydzh3r (31/08/2024 - present) ##### /authors ##### ##### translated strings ##### @@ -16,7 +17,7 @@ [Demo player duration] %d min. -== %dхв +== %d хв. %d new mentions == Нових згадок: %d @@ -39,7 +40,7 @@ [Demo player duration] %d sec. -== %dс +== %d сек. %d/%d KiB (%.1f KiB/s) == %d/%d КіБ (%.1f КіБ/с) @@ -52,16 +53,16 @@ == залишилося %dс %i minute left -== Залишилося: %iхв +== Залишилося: %i хв. %i minutes left -== Залишилося: %iхв +== Залишилося: %i хв. %i second left -== Залишилося: %iс +== Залишилося: %i сек. %i seconds left -== Залишилося: %iс +== Залишилося: %i сек. %s wins! == %s перемагає! @@ -86,7 +87,7 @@ A render command failed. Try to update your GPU drivers. == Помилка в команді відмальовування. Спробуйте оновити драйвери відеокарти. A Tee -== тії +== Тії Abort == Скасувати @@ -175,13 +176,13 @@ Are you sure that you want to delete the folder '%s'? == Ви дійсно хочете видалити теку '%s'? Are you sure that you want to disconnect? -== Ви дійсно хочете від'єднатися? +== Ви дійсно хочете від’єднатися? Are you sure that you want to disconnect and switch to a different server? -== Ви дійсно хочете від'єднатися й приєднатися до іншого сервера? +== Ви дійсно хочете від’єднатися й приєднатися до іншого сервера? Are you sure that you want to disconnect your dummy? -== Ви дійсно хочете від'єднати свого даммі? +== Ви дійсно хочете від’єднати свого даммі? Are you sure that you want to quit? == Ви дійсно хочете вийти? @@ -193,7 +194,7 @@ Are you sure that you want to remove the player '%s' from your friends list? == Ви дійсно хочете прибрати гравця '%s' зі списку друзів? Are you sure that you want to reset the controls to their defaults? -== Ви дійсно хочете скинути налаштування керування до значень за замовчуванням? +== Ви дійсно хочете скинути налаштування керувань до стандартних значень? Are you sure that you want to restart? == Ви дійсно хочете перезапустити? @@ -205,13 +206,13 @@ Assets == Текстури Assets directory -== Тека текстур +== Тека ресурсів AUS == АВС Authed name color in scoreboard -== Колір авторизованих у таблі +== Колір авторизованих у таблиці Auto == Авто @@ -220,7 +221,7 @@ auto == автоматично Automatically create statboard csv -== Автоматично зберігати статистику у CSV-файл +== Автоматично зберігати статистику у файл CSV Automatically record demos == Автоматично записувати демо @@ -235,7 +236,7 @@ Axis == Осі Background -== Фон +== Тло Background music volume == Гучність фонової музики @@ -295,13 +296,13 @@ Check now == Перевірити Checking for existing player with your name -== Перевіряємо Ваш нікнейм на доступність +== Перевірка на наявність гравця з вашим ім’ям CHN == КИТ Choose default eyes when joining a server -== Очі, які відображатимуться за замовчуванням +== Стандартні очі під час приєднання до сервера Clan == Клан @@ -328,7 +329,7 @@ Close the demo player == Закрити програвач демо Colors of the hook collision line, in case of a possible collision with: -== Кольори лінії зіткнення гака, якщо він може зіштовхнутися з: +== Кольори лінії зіткнення гака, в разі можливого зіткнення з: Communities == Спільноти @@ -337,28 +338,28 @@ Config directory == Тека налаштувань Connect address error -== Помилка адреси з'єднання +== Помилка адреси з’єднання Connect Dummy -== Приєднати даммі +== Під’єднати даммі Connected -== Приєднано +== Під’єднано Connecting dummy -== Приєднуємо даммі +== Під’єднати даммі Connecting to -== Приєднуємося до +== Під’єднання до Connection Problems… -== Проблеми зі з'єднанням… +== Проблеми зі з’єднанням… Console == Консоль Continue anyway? -== Все одно продовжити? +== Усе одно продовжити? Controller == Контролер @@ -376,24 +377,24 @@ Copy info == Скопіювати Could not connect dummy -== Не вдалося під'єднати даммі +== Не вдалося під’єднати даммі [Graphics error] Could not initialize the given graphics backend, reverting to the default backend now. -== Не вдалося ініціалізувати заданий графічний рушій, повертаємося до рушія за замовчуванням. +== Не вдалося ініціалізувати заданий графічний рушій, повертаємося до стандартного рушія. [Graphics error] Could not initialize the given graphics backend, this is probably because you didn't install the driver of the integrated graphics card. -== Не вдалося ініціалізувати заданий графічний рушій, можливо тому що ви не встановили драйвери на вбудовану відеокарту. +== Не вдалося ініціалізувати заданий графічний рушій, імовірно, ви не встановили драйвери на вбудовану відеокарту. Could not resolve connect address '%s'. See local console for details. -== Не вдалося визначити адресу з'єднання '%s' (див. локальну консоль). +== Не вдалося визначити адресу з’єднання '%s'. Див. локальну консоль для подробиць. Could not save downloaded map. Try manually deleting this file: %s == Не вдалося зберегти завантажену мапу. Спробуйте самостійно видалити цей файл: %s Count players only -== Рахувати тільки гравців +== Рахувати лише гравців Countries == Країни @@ -417,7 +418,7 @@ Custom colors == Власні кольори Customize -== Налаштування +== Налаштувати Cut interval == Інтервал @@ -438,7 +439,7 @@ DDNet %s is out! == Вийшов DDNet %s! DDNet Client needs to be restarted to complete update! -== Потрібно перезапустити клієнт DDNet, щоб завершити оновлення! +== Потрібно перезапустити клієнт DDNet для завершення оновлення! DDNet Client updated! == Клієнт DDNet оновлено! @@ -447,7 +448,7 @@ DDRace HUD == HUD DDRace DDraceNetwork is a cooperative online game where the goal is for you and your group of tees to reach the finish line of the map. As a newcomer you should start on Novice servers, which host the easiest maps. Consider the ping to choose a server close to you. -== DDraceNetwork — кооперативна мережева гра, ціль якої — дістатися разом зі своєю групою тії до фінішної прямої. Новачкам варто почати із серверів "Для новачків" (Novice), на яких є найпростіші мапи. Зважайте на затримку, коли вибираєте сервер. +== DDraceNetwork — кооперативна мережева гра, ціль якої — дістатися разом зі своєю групою тії до фінішної прямої. Новачкам варто почати із серверів «Для новачків» (Novice), на яких є найпростіші мапи. Зважайте на затримку, коли вибираєте сервер. Deactivate == Деактивувати @@ -456,13 +457,13 @@ Deactivate all == Деактивувати усіх Deaths -== С +== Смерті Debug mode enabled. Press Ctrl+Shift+D to disable debug mode. == Увімкнено режим налагодження. Натисніть Ctrl+Shift+D, щоб його вимкнути. default -== за замовчуванням +== за стандартом Default length == Звичайна тривалість @@ -495,16 +496,16 @@ Demos directory == Тека демо Desktop fullscreen -== Стільничний повноекранний +== Робочий стіл на весь екран Disconnect -== Від'єднатися +== Від’єднатися Disconnect Dummy -== Від'єднати даммі +== Від’єднати даммі Disconnected -== Від'єднано +== Від’єднано Discord == Discord @@ -522,10 +523,10 @@ Download skins == Завантажувати скіни Downloading %s: -== Завантажуємо %s: +== Завантаження %s: Downloading map -== Завантажуємо мапу +== Завантаження мапи Draw! == Нічия! @@ -543,7 +544,7 @@ Dummy settings == Налаштування даммі Dynamic Camera -== Рухома камера +== Динамічна камера Editor == Редактор @@ -576,7 +577,7 @@ Enable regular chat sound == Звук звичайного повідомлення Enable replays -== Повтори +== Увімкнути повтори Enable server message sound == Звук повідомлення сервера @@ -588,13 +589,13 @@ Enter Password == Введіть пароль Enter Username -== Введіть логін +== Введіть ім’я користувача Entities == Сутності Entities background color -== Колір фону сутностей +== Колір тла сутностей Error == Помилка @@ -609,16 +610,16 @@ Error saving settings == Помилка збереження налаштувань EUR -== ЄВР +== EUR Example of usage -== Наприклад +== Приклад використання Exclude == Виключити Existing Player -== Гравець вже існує +== Гравець уже існує Export cut as a separate demo == Експортувати фрагмент як окреме демо @@ -681,7 +682,7 @@ Following [Spectating] Following %s -== Слідуємо за %s +== Cпостерігання за %s Force vote == Форсувати @@ -711,7 +712,7 @@ FSAA samples == Вибірка FSAA Fullscreen -== Повноекранний +== На весь екран Game == Гра @@ -738,13 +739,13 @@ Gameplay == Ігролад General -== Загальне +== Загальні Getting game info -== Отримуємо інформацію про гру +== Отримання інформації про гру Getting server list from master server -== Отримуємо список серверів з головного сервера +== Отримання списку серверів з головного сервера Ghost == Привид @@ -756,7 +757,7 @@ Go back one marker == Перемотати до попередньої мітки Go back one tick -== Перемотати вперед на один тік +== Перемотати вперед на один такт Go back the specified duration == Перемотати назад @@ -765,7 +766,7 @@ Go forward one marker == Перемотати до наступної мітки Go forward one tick -== Перемотати назад на один тік +== Перемотати вперед на один такт Go forward the specified duration == Перемотати вперед @@ -831,31 +832,31 @@ HUD == HUD Hue -== Тон +== Відтінок Indicate map finish == Позначати пройдені мапи Info Messages -== Інфо-повідомлення +== Інформаційні повідомлення Ingame controller mode == Режим контролера у грі Ingame controller sens. -== Чутл. у грі +== Чутливість у грі Ingame mouse sens. -== Чутл. у грі +== Чутливість у грі Initializing assets -== Ініціалізуємо текстури +== Ініціалізація текстур Initializing components -== Ініціалізуємо компоненти +== Ініціалізація компонентів Initializing map logic -== Ініціалізуємо логіку мапи +== Ініціалізація логіки мапи Internet == Інтернет @@ -864,7 +865,7 @@ Invalid Demo == Недійсне демо It's recommended that you check the settings to adjust them to your liking before joining a server. -== Перед тим як приєднатися до сервера, рекомендуємо змінити налаштування до ваших уподобань. +== Перед тим, як приєднатися до сервера, рекомендуємо змінити налаштування до ваших уподобань. Join blue == До синіх @@ -909,58 +910,58 @@ Lht. == Світл. Lines %d - %d (%s) -== Рядки %d—%d (%s) +== Рядки %d — %d (%s) Loading… == Завантаження… Loading assets -== Завантажуємо текстури +== Завантаження текстур Loading commands… -== Завантажуємо команди… +== Завантаження команд… Loading DDNet Client -== Завантажуємо клієнт DDNet +== Завантаження клієнта DDNet Loading demo file from storage -== Завантажуємо демо-файл зі сховища +== Завантаження демо-файла зі сховища Loading demo files -== Завантажуємо демо-файли +== Завантаження демо-файлів Loading ghost files -== Завантажуємо файли привида +== Завантаження файлів привида Loading map file from storage -== Завантажуємо файл мапи зі сховища +== Завантаження файлу мапи зі сховища Loading menu images -== Завантажуємо зображення меню +== Завантаження зображень меню Loading menu themes -== Завантажуємо теми меню +== Завантаження тем меню Loading race demo files -== Завантажуємо демо-файли забігів +== Завантаження демо-файлів забігів Loading skin files -== Завантажуємо файли скінів +== Завантаження файлів скінів Loading sound files -== Завантажуємо звукові файли +== Завантаження звукових файлів Lock team == Замкнути команду Locked -== Заблоковано +== Замкнено Main menu == Головне меню Manual -== Вручну +== Уручну Map == Мапа @@ -1063,16 +1064,16 @@ Next weapon == Наст. зброя Nickname -== Нікнейм +== Псевдонім No == Ні No answer from server yet. -== Сервер ще не відповів. +== Поки що немає відповіді від сервера. No controller found. Plug in a controller. -== Жодного контролера не знайдено. Підключіть контролер. +== Жодного контролера не знайдено. Під’єднайте контролер. No demo selected == Жодного демо не вибрано @@ -1111,29 +1112,29 @@ Normal message == Звичайні повідомлення NOT CONNECTED -== НЕ ПРИЄДНАНО +== НЕ ПІД’ЄДНАНО Nothing hookable == нічим, за що можна зачепитися [friends (server browser)] Offline (%d) -== Офлайн (%d) +== Не в мережі (%d) Ok == Гаразд Online clanmates (%d) -== Онлайн клановці (%d) +== Співклановці в мережі (%d) Online players (%d) -== Онлайн гравці (%d) +== Гравці в мережі (%d) Only save improvements == Зберігати лише покращення Opacity -== Непрозор. +== Непрозорість Opacity of freeze bars inside freeze == Непрозорість смуги заморозки в заморозці @@ -1158,7 +1159,7 @@ Open the settings file [Graphics error] Out of VRAM. Try removing custom assets (skins, entities, etc.), especially those with high resolution. -== Недостатньо відеопам'яті. Спробуйте видалити власні текстури (скіни, сутності і т.п.), особливо ті, що мають високу роздільну здатність. +== Недостатньо відеопам’яті. Спробуйте видалити власні текстури (скіни, сутності і т.п.), особливо ті, що мають високу роздільність. Overlay entities == Накладати сутності @@ -1167,10 +1168,10 @@ Parent Folder == Батьківська тека Particles -== Часточки +== Частинки Pause -== Пауза +== Павза Pause the current demo == Призупинити @@ -1228,7 +1229,7 @@ Position: == Позиція: Preparing demo playback -== Підготовлюємо відтворення демо +== Підготовлення відтворення демо Press a key… == Натисніть клавішу… @@ -1243,7 +1244,7 @@ Quads are used for background decoration == Квади використовуються для декорацій Quit -== Вихід +== Вийти Quitting. Please wait… == Вихід. Будь ласка, зачекайте… @@ -1252,7 +1253,7 @@ Race == Забіг Randomize -== Випадково +== Навмання Ratio == У/С @@ -1261,7 +1262,7 @@ Reason: == Причина: Reconnect in %d sec -== Переприєднання через %dс +== Повторне під’єднання за %d сек. Record demo == Запис демо @@ -1273,10 +1274,10 @@ Red team wins! == Червоні перемогли! Refresh Rate -== Частота кадрів +== Частота оновлення Regular background color -== Колір звичайного фону +== Колір звичайного тла [Ingame controller mode] Relative @@ -1319,10 +1320,10 @@ Replay == Повтор Replay feature is disabled! -== Повтори відключено! +== Повтори вимкнено! Requesting to join the game -== Запитуємо приєднання до гри +== Запит на приєднання до гри Reset == Скинути @@ -1334,7 +1335,7 @@ Reset filter == Скинути фільтр Reset to defaults -== Скинути +== Скинути до типових Restart == Перезапустити @@ -1361,10 +1362,10 @@ SA == ПДА Same clan color in scoreboard -== Колір співклановців у таблі +== Колір співклановців у таблиці Sat. -== Насич. +== Насиченість Save == Зберегти @@ -1373,7 +1374,7 @@ Save ghost == Зберігати привида Save power by lowering refresh rate (higher input latency) -== Зберігати енергію зниженням частоти кадрів (вища затримка вводу) +== Економія енергії шляхом зниження частоти оновлення (вища затримка введення) Save the best demo of each race == Зберігати найкраще демо кожного забігу @@ -1388,7 +1389,7 @@ Score limit == Гра до Scoreboard -== Табло +== Таблиця Screen == Екран @@ -1400,10 +1401,10 @@ Search == Пошук Searching -== Шукаємо +== Пошук Sending initial client info -== Надсилаємо початкові дані клієнта +== Надсилання початкових даних клієнта Server address: == Адреса сервера: @@ -1424,7 +1425,7 @@ Server not full == Неповний сервер Set all to Rifle -== Встановити так, як у гвинтівки +== Установити так, як у гвинтівки Settings == Налаштування @@ -1463,7 +1464,7 @@ Show dummy actions == Показувати дії з даммі Show entities -== Сутності +== Показувати сутності Show finish messages == Показувати повідомлення про фініші @@ -1472,7 +1473,7 @@ Show freeze bars == Показувати смугу заморозки Show friend mark (♥) in name plates -== Показувати позначку друга (♥) біля ніків +== Показувати позначку друга (♥) біля псевдонімів Show friends only == Показувати лише з друзями @@ -1481,10 +1482,10 @@ Show ghost == Показувати привида Show health, shields and ammo -== Показувати здоров'я, щити й набої +== Показувати здоров’я, захист і набої Show hook strength icon indicator -== Показувати графічний індикатор сили гака +== Показувати іконку індикатора сили гака Show hook strength number indicator == Показувати числовий індикатор сили гака @@ -1508,10 +1509,10 @@ Show local time always == Завжди показувати місцевий час Show name plates -== Показувати ніки +== Показувати псевдоніми Show names in chat in team colors -== Фарбувати ніки в чаті в кольори команд +== Показувати імена в чаті в кольорах команди Show only chat messages from friends == Показувати лише повідомлення від друзів @@ -1550,7 +1551,7 @@ Show text entities == Текстові сутності Show tiles layers from BG map -== Показувати тайли з мапи фону +== Показувати плитки з мапи фону Show quads == Показувати квади @@ -1580,13 +1581,13 @@ Slow down the demo == Сповільнити Smooth Dynamic Camera -== Гладка рухома камера +== Гладка динамічна камера Some map images could not be loaded. Check the local console for details. -== Деякі зображення мапи не завантажилися. Деталі у локальній консолі. +== Деякі зображення мапи не завантажилися. Див. локальну консоль для подробиць. Some map sounds could not be loaded. Check the local console for details. -== Деякі звуки мапи не завантажилися. Деталі у локальній консолі. +== Деякі звуки мапи не завантажилися. Див. локальну консоль для подробиць. Something hookable == чимось, за що можна зачепитися @@ -1610,10 +1611,10 @@ Spectate previous == Попер. гравець Spectator mode -== Режим спостерігача +== Режим глядача Spectators -== Спостерігачі +== Глядачі Speed == Швидкість @@ -1767,10 +1768,10 @@ UI Color == Колір інтерфейсу UI controller sens. -== Чутл. у інтерфейсі +== Чутливість в інтерфейсі UI mouse sens. -== Чутл. у інтерфейсі +== Чутливість в інтерфейсі Unable to delete skin == Не вдалося видалити скін @@ -1798,25 +1799,25 @@ Unregister protocol and file extensions == Розреєструвати протокол і розширення файлів Update failed! Check log… -== Оновлення не вдалося! Перевірте журнал… +== Помилка оновлення! Перевірте журнал… Update now == Оновити Updating… -== Оновлюємо… +== Оновлення… Uploading map data to GPU -== Вивантажуємо дані мапи до відеокарти +== Вивантаження даних мапи до відеокарти Use current map as background -== Використовувати поточну мапу як фон +== Використовувати поточну мапу як тло Use high DPI == Високий DPI Use k key to kill (restart), q to pause and watch other players. See settings for other key binds. -== Натисніть "k", щоб умерти (почати спочатку), "q", щоб спостерігати за іншими гравцями. Інші скорочення дивіться у налаштуваннях. +== Натисніть «k», щоб умерти (почати спочатку), «q», щоб спостерігати за іншими гравцями. Інші призначення клавіш дивіться у налаштуваннях. Use old chat style == Старий стиль чату @@ -1885,13 +1886,13 @@ Why are you slowmo replaying to read this? == Чому ви переглядаєте це у повторі? Windowed -== Віконний +== У вікні Windowed borderless -== Віконний без рамок +== Вікно без рамок Windowed fullscreen -== Віконний повноекранний +== Вікно на весь екран Yes == Так @@ -1903,7 +1904,7 @@ You must restart the game for all settings to take effect. == Щоб налаштування набрали чинності, перезапустіть гру. Your nickname '%s' is already used (%d points). Do you still want to use it? -== Нікнейм '%s' вже зайнято (%d балів). Все ще хочете використовувати його? +== Ваш псевдонім «%s» вже зайнято (%d балів). Усе ще хочете використовувати його? Your skin == Ваш скін From f44def1cddf5866f0485bbf2ac38fa06d8dec662 Mon Sep 17 00:00:00 2001 From: ChillerDragon Date: Sat, 31 Aug 2024 18:56:21 +0800 Subject: [PATCH 14/30] Only do armor progress hack in ddrace controller Only mess with the characters armor in ddrace controllers. This allows other game modes to use the armor as actual armor. --- src/game/server/entities/character.cpp | 4 ++-- src/game/server/gamecontroller.h | 1 + src/game/server/gamemodes/DDRace.cpp | 5 +++++ src/game/server/gamemodes/DDRace.h | 1 + 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/game/server/entities/character.cpp b/src/game/server/entities/character.cpp index 59f078297ce..8e60014e814 100644 --- a/src/game/server/entities/character.cpp +++ b/src/game/server/entities/character.cpp @@ -260,7 +260,7 @@ void CCharacter::HandleNinja() GameServer()->CreateDamageInd(m_Pos, 0, NinjaTime / Server()->TickSpeed(), TeamMask() & GameServer()->ClientsMaskExcludeClientVersionAndHigher(VERSION_DDNET_NEW_HUD)); } - m_Armor = clamp(10 - (NinjaTime / 15), 0, 10); + GameServer()->m_pController->SetArmorProgress(this, NinjaTime); // force ninja Weapon SetWeapon(WEAPON_NINJA); @@ -2055,7 +2055,7 @@ void CCharacter::ForceSetRescue(int RescueMode) void CCharacter::DDRaceTick() { mem_copy(&m_Input, &m_SavedInput, sizeof(m_Input)); - m_Armor = clamp(10 - (m_FreezeTime / 15), 0, 10); + GameServer()->m_pController->SetArmorProgress(this, m_FreezeTime); if(m_Input.m_Direction != 0 || m_Input.m_Jump != 0) m_LastMove = Server()->Tick(); diff --git a/src/game/server/gamecontroller.h b/src/game/server/gamecontroller.h index 3f80e67eb80..a732123b4e1 100644 --- a/src/game/server/gamecontroller.h +++ b/src/game/server/gamecontroller.h @@ -95,6 +95,7 @@ class IGameController virtual void OnCharacterSpawn(class CCharacter *pChr); virtual void HandleCharacterTiles(class CCharacter *pChr, int MapIndex); + virtual void SetArmorProgress(CCharacter *pCharacer, int Progress){}; /* Function: OnEntity diff --git a/src/game/server/gamemodes/DDRace.cpp b/src/game/server/gamemodes/DDRace.cpp index da14b863abd..a2959a885d0 100644 --- a/src/game/server/gamemodes/DDRace.cpp +++ b/src/game/server/gamemodes/DDRace.cpp @@ -112,6 +112,11 @@ void CGameControllerDDRace::HandleCharacterTiles(CCharacter *pChr, int MapIndex) } } +void CGameControllerDDRace::SetArmorProgress(CCharacter *pCharacer, int Progress) +{ + pCharacer->SetArmor(clamp(10 - (Progress / 15), 0, 10)); +} + void CGameControllerDDRace::OnPlayerConnect(CPlayer *pPlayer) { IGameController::OnPlayerConnect(pPlayer); diff --git a/src/game/server/gamemodes/DDRace.h b/src/game/server/gamemodes/DDRace.h index 17626f26a3d..bc307e0538c 100644 --- a/src/game/server/gamemodes/DDRace.h +++ b/src/game/server/gamemodes/DDRace.h @@ -13,6 +13,7 @@ class CGameControllerDDRace : public IGameController CScore *Score(); void HandleCharacterTiles(class CCharacter *pChr, int MapIndex) override; + void SetArmorProgress(CCharacter *pCharacer, int Progress) override; void OnPlayerConnect(class CPlayer *pPlayer) override; void OnPlayerDisconnect(class CPlayer *pPlayer, const char *pReason) override; From f8a4e7dbab5960090c33f858af621351d0dc71a7 Mon Sep 17 00:00:00 2001 From: ChillerDragon Date: Sat, 31 Aug 2024 19:16:26 +0800 Subject: [PATCH 15/30] Call TakeDamage on projectile and laser hit (gun, shotgun and laser) The grenade and hammer already triggered TakeDamage now all weapons hitting a tee call the method again --- src/game/server/entities/laser.cpp | 1 + src/game/server/entities/projectile.cpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/game/server/entities/laser.cpp b/src/game/server/entities/laser.cpp index 6c393c5b748..ba15d94f5ac 100644 --- a/src/game/server/entities/laser.cpp +++ b/src/game/server/entities/laser.cpp @@ -94,6 +94,7 @@ bool CLaser::HitCharacter(vec2 From, vec2 To) { pHit->UnFreeze(); } + pHit->TakeDamage(vec2(0, 0), 0, m_Owner, m_Type); return true; } diff --git a/src/game/server/entities/projectile.cpp b/src/game/server/entities/projectile.cpp index 9579b017047..c2bdac75fd6 100644 --- a/src/game/server/entities/projectile.cpp +++ b/src/game/server/entities/projectile.cpp @@ -177,6 +177,8 @@ void CProjectile::Tick() pChr->Freeze(); } } + else if(pTargetChr) + pTargetChr->TakeDamage(vec2(0, 0), 0, m_Owner, m_Type); if(pOwnerChar && !GameLayerClipped(ColPos) && ((m_Type == WEAPON_GRENADE && pOwnerChar->HasTelegunGrenade()) || (m_Type == WEAPON_GUN && pOwnerChar->HasTelegunGun()))) From f053a2946345f44c5bf1d7e7cd30dc1dc87b192c Mon Sep 17 00:00:00 2001 From: ChillerDragon Date: Sun, 11 Feb 2024 12:14:37 +0800 Subject: [PATCH 16/30] Add ctrl+p editor prompt (quick actions) --- CMakeLists.txt | 5 + src/game/editor/editor.cpp | 29 +++--- src/game/editor/editor.h | 15 ++- src/game/editor/popups.cpp | 15 +-- src/game/editor/prompt.cpp | 166 ++++++++++++++++++++++++++++++ src/game/editor/prompt.h | 29 ++++++ src/game/editor/quick_action.h | 58 +++++++++++ src/game/editor/quick_actions.cpp | 20 ++++ src/game/editor/quick_actions.h | 50 +++++++++ 9 files changed, 358 insertions(+), 29 deletions(-) create mode 100644 src/game/editor/prompt.cpp create mode 100644 src/game/editor/prompt.h create mode 100644 src/game/editor/quick_action.h create mode 100644 src/game/editor/quick_actions.cpp create mode 100644 src/game/editor/quick_actions.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 90741753214..99cfe65100a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2500,8 +2500,13 @@ if(CLIENT) mapitems/sound.cpp mapitems/sound.h popups.cpp + prompt.cpp + prompt.h proof_mode.cpp proof_mode.h + quick_action.h + quick_actions.cpp + quick_actions.h smooth_value.cpp smooth_value.h tileart.cpp diff --git a/src/game/editor/editor.cpp b/src/game/editor/editor.cpp index ea6a8865e36..978716bbf93 100644 --- a/src/game/editor/editor.cpp +++ b/src/game/editor/editor.cpp @@ -1074,11 +1074,9 @@ void CEditor::DoToolbarLayers(CUIRect ToolBar) // proof button TB_Top.VSplitLeft(40.0f, &Button, &TB_Top); - static int s_ProofButton = 0; - if(DoButton_Ex(&s_ProofButton, "Proof", MapView()->ProofMode()->IsEnabled(), &Button, 0, "[ctrl+p] Toggles proof borders. These borders represent the area that a player can see with default zoom.", IGraphics::CORNER_L) || - (m_Dialog == DIALOG_NONE && CLineInput::GetActiveInput() == nullptr && Input()->KeyPress(KEY_P) && ModPressed)) + if(DoButton_Ex(&m_QuickActionProof, m_QuickActionProof.Label(), m_QuickActionProof.Active(), &Button, 0, m_QuickActionProof.Description(), IGraphics::CORNER_L)) { - MapView()->ProofMode()->Toggle(); + m_QuickActionProof.Call(); } TB_Top.VSplitLeft(14.0f, &Button, &TB_Top); @@ -1254,10 +1252,9 @@ void CEditor::DoToolbarLayers(CUIRect ToolBar) // refocus button { TB_Bottom.VSplitLeft(50.0f, &Button, &TB_Bottom); - static int s_RefocusButton = 0; int FocusButtonChecked = MapView()->IsFocused() ? -1 : 1; - if(DoButton_Editor(&s_RefocusButton, "Refocus", FocusButtonChecked, &Button, 0, "[HOME] Restore map focus") || (m_Dialog == DIALOG_NONE && CLineInput::GetActiveInput() == nullptr && Input()->KeyPress(KEY_HOME))) - MapView()->Focus(); + if(DoButton_Editor(&m_QuickActionRefocus, m_QuickActionRefocus.Label(), FocusButtonChecked, &Button, 0, m_QuickActionRefocus.Description()) || (m_Dialog == DIALOG_NONE && CLineInput::GetActiveInput() == nullptr && Input()->KeyPress(KEY_HOME))) + m_QuickActionRefocus.Call(); TB_Bottom.VSplitLeft(5.0f, nullptr, &TB_Bottom); } @@ -4302,12 +4299,9 @@ void CEditor::RenderLayers(CUIRect LayersBox) if(s_ScrollRegion.AddRect(AddGroupButton)) { AddGroupButton.HSplitTop(RowHeight, &AddGroupButton, 0); - static int s_AddGroupButton = 0; - if(DoButton_Editor(&s_AddGroupButton, "Add group", 0, &AddGroupButton, IGraphics::CORNER_R, "Adds a new group")) + if(DoButton_Editor(&m_QuickActionAddGroup, m_QuickActionAddGroup.Label(), 0, &AddGroupButton, IGraphics::CORNER_R, m_QuickActionAddGroup.Description())) { - m_Map.NewGroup(); - m_SelectedGroup = m_Map.m_vpGroups.size() - 1; - m_EditorHistory.RecordAction(std::make_shared(this, m_SelectedGroup, false)); + m_QuickActionAddGroup.Call(); } } @@ -4806,8 +4800,8 @@ void CEditor::RenderImagesList(CUIRect ToolBox) { AddImageButton.HSplitTop(5.0f, nullptr, &AddImageButton); AddImageButton.HSplitTop(RowHeight, &AddImageButton, nullptr); - if(DoButton_Editor(&s_AddImageButton, "Add", 0, &AddImageButton, 0, "Load a new image to use in the map")) - InvokeFileDialog(IStorage::TYPE_ALL, FILETYPE_IMG, "Add Image", "Add", "mapres", false, AddImage, this); + if(DoButton_Editor(&s_AddImageButton, m_QuickActionAddImage.Label(), 0, &AddImageButton, 0, m_QuickActionAddImage.Description())) + m_QuickActionAddImage.Call(); } s_ScrollRegion.End(); } @@ -5750,9 +5744,9 @@ void CEditor::RenderStatusbar(CUIRect View, CUIRect *pTooltipRect) CUIRect Button; View.VSplitRight(100.0f, &View, &Button); static int s_EnvelopeButton = 0; - if(DoButton_Editor(&s_EnvelopeButton, "Envelopes", ButtonsDisabled ? -1 : m_ActiveExtraEditor == EXTRAEDITOR_ENVELOPES, &Button, 0, "Toggles the envelope editor.") == 1) + if(DoButton_Editor(&s_EnvelopeButton, m_QuickActionEnvelopes.Label(), m_QuickActionEnvelopes.Color(), &Button, 0, m_QuickActionEnvelopes.Description()) == 1) { - m_ActiveExtraEditor = m_ActiveExtraEditor == EXTRAEDITOR_ENVELOPES ? EXTRAEDITOR_NONE : EXTRAEDITOR_ENVELOPES; + m_QuickActionEnvelopes.Call(); } View.VSplitRight(10.0f, &View, nullptr); @@ -7919,7 +7913,7 @@ void CEditor::Render() InvokeFileDialog(IStorage::TYPE_SAVE, FILETYPE_MAP, "Save map", "Save", "maps", true, CallbackSaveCopyMap, this); // ctrl+shift+s to save as else if(Input()->KeyPress(KEY_S) && ModPressed && ShiftPressed) - InvokeFileDialog(IStorage::TYPE_SAVE, FILETYPE_MAP, "Save map", "Save", "maps", true, CallbackSaveMap, this); + m_QuickActionSaveAs.Call(); // ctrl+s to save else if(Input()->KeyPress(KEY_S) && ModPressed) { @@ -8362,6 +8356,7 @@ void CEditor::Init() m_vComponents.emplace_back(m_MapView); m_vComponents.emplace_back(m_MapSettingsBackend); m_vComponents.emplace_back(m_LayerSelector); + m_vComponents.emplace_back(m_Prompt); for(CEditorComponent &Component : m_vComponents) Component.OnInit(this); diff --git a/src/game/editor/editor.h b/src/game/editor/editor.h index bead2c2171a..8b5212a1a98 100644 --- a/src/game/editor/editor.h +++ b/src/game/editor/editor.h @@ -38,6 +38,8 @@ #include "layer_selector.h" #include "map_view.h" #include "smooth_value.h" +#include +#include #include #include @@ -60,7 +62,8 @@ enum DIALOG_NONE = 0, DIALOG_FILE, - DIALOG_MAPSETTINGS_ERROR + DIALOG_MAPSETTINGS_ERROR, + DIALOG_QUICK_PROMPT, }; class CEditorImage; @@ -278,6 +281,7 @@ class CEditor : public IEditor std::vector> m_vComponents; CMapView m_MapView; CLayerSelector m_LayerSelector; + CPrompt m_Prompt; bool m_EditorWasUsedBefore = false; @@ -319,7 +323,16 @@ class CEditor : public IEditor const CMapView *MapView() const { return &m_MapView; } CLayerSelector *LayerSelector() { return &m_LayerSelector; } + void AddGroup(); + void AddTileLayer(); +#define REGISTER_QUICK_ACTION(name, text, callback, disabled, active, button_color, description) CQuickAction m_QuickAction##name; +#include +#undef REGISTER_QUICK_ACTION + CEditor() : +#define REGISTER_QUICK_ACTION(name, text, callback, disabled, active, button_color, description) m_QuickAction##name(text, description, callback, disabled, active, button_color), +#include +#undef REGISTER_QUICK_ACTION m_ZoomEnvelopeX(1.0f, 0.1f, 600.0f), m_ZoomEnvelopeY(640.0f, 0.1f, 32000.0f), m_MapSettingsCommandContext(m_MapSettingsBackend.NewContext(&m_SettingsCommandInput)) diff --git a/src/game/editor/popups.cpp b/src/game/editor/popups.cpp index 22dc9d07f28..45844b64a0d 100644 --- a/src/game/editor/popups.cpp +++ b/src/game/editor/popups.cpp @@ -107,9 +107,9 @@ CUi::EPopupMenuFunctionResult CEditor::PopupMenuFile(void *pContext, CUIRect Vie View.HSplitTop(2.0f, nullptr, &View); View.HSplitTop(12.0f, &Slot, &View); - if(pEditor->DoButton_MenuItem(&s_SaveAsButton, "Save As", 0, &Slot, 0, "Saves the current map under a new name (ctrl+shift+s)")) + if(pEditor->DoButton_MenuItem(&s_SaveAsButton, pEditor->m_QuickActionSaveAs.Label(), 0, &Slot, 0, pEditor->m_QuickActionSaveAs.Description())) { - pEditor->InvokeFileDialog(IStorage::TYPE_SAVE, FILETYPE_MAP, "Save map", "Save", "maps", true, CEditor::CallbackSaveMap, pEditor); + pEditor->m_QuickActionSaveAs.Call(); return CUi::POPUP_CLOSE_CURRENT; } @@ -578,16 +578,9 @@ CUi::EPopupMenuFunctionResult CEditor::PopupGroup(void *pContext, CUIRect View, // new tile layer View.HSplitBottom(5.0f, &View, nullptr); View.HSplitBottom(12.0f, &View, &Button); - static int s_NewTileLayerButton = 0; - if(pEditor->DoButton_Editor(&s_NewTileLayerButton, "Add tile layer", 0, &Button, 0, "Creates a new tile layer")) + if(pEditor->DoButton_Editor(&pEditor->m_QuickActionAddTileLayer, pEditor->m_QuickActionAddTileLayer.Label(), 0, &Button, 0, pEditor->m_QuickActionAddTileLayer.Description())) { - std::shared_ptr pTileLayer = std::make_shared(pEditor, pEditor->m_Map.m_pGameLayer->m_Width, pEditor->m_Map.m_pGameLayer->m_Height); - pTileLayer->m_pEditor = pEditor; - pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->AddLayer(pTileLayer); - int LayerIndex = pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_vpLayers.size() - 1; - pEditor->SelectLayer(LayerIndex); - pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->m_Collapse = false; - pEditor->m_EditorHistory.RecordAction(std::make_shared(pEditor, pEditor->m_SelectedGroup, LayerIndex)); + pEditor->m_QuickActionAddTileLayer.Call(); return CUi::POPUP_CLOSE_CURRENT; } diff --git a/src/game/editor/prompt.cpp b/src/game/editor/prompt.cpp new file mode 100644 index 00000000000..213466bf5bc --- /dev/null +++ b/src/game/editor/prompt.cpp @@ -0,0 +1,166 @@ +#include +#include +#include + +#include "editor.h" + +#include "prompt.h" + +bool FuzzyMatch(const char *pHaystack, const char *pNeedle) +{ + if(!pNeedle || !pNeedle[0]) + return false; + char aBuf[2] = {0}; + const char *pHit = pHaystack; + int NeedleLen = str_length(pNeedle); + for(int i = 0; i < NeedleLen; i++) + { + if(!pHit) + return false; + aBuf[0] = pNeedle[i]; + pHit = str_find_nocase(pHit, aBuf); + if(pHit) + pHit++; + } + return pHit; +} + +bool CPrompt::IsActive() +{ + return CEditorComponent::IsActive() || Editor()->m_Dialog == DIALOG_QUICK_PROMPT; +} + +void CPrompt::SetActive() +{ + Editor()->m_Dialog = DIALOG_QUICK_PROMPT; + CEditorComponent::SetActive(); + + Ui()->SetActiveItem(&m_PromptInput); +} + +void CPrompt::SetInactive() +{ + m_ResetFilterResults = true; + m_PromptInput.Clear(); + if(Editor()->m_Dialog == DIALOG_QUICK_PROMPT) + Editor()->m_Dialog = DIALOG_NONE; + CEditorComponent::SetInactive(); +} + +bool CPrompt::OnInput(const IInput::CEvent &Event) +{ + if(Input()->ModifierIsPressed() && Input()->KeyIsPressed(KEY_P)) + { + SetActive(); + } + return false; +} + +void CPrompt::OnInit(CEditor *pEditor) +{ + CEditorComponent::OnInit(pEditor); + +#define REGISTER_QUICK_ACTION(name, text, callback, disabled, active, button_color, description) m_vQuickActions.emplace_back(&Editor()->m_QuickAction##name); +#include +#undef REGISTER_QUICK_ACTION +} + +void CPrompt::OnRender(CUIRect _) +{ + if(!IsActive()) + return; + + if(Ui()->ConsumeHotkey(CUi::HOTKEY_ESCAPE)) + { + SetInactive(); + return; + } + + static CListBox s_ListBox; + CUIRect Prompt, PromptBox; + CUIRect Suggestions; + + Ui()->MapScreen(); + CUIRect Overlay = *Ui()->Screen(); + + Overlay.Draw(ColorRGBA(0, 0, 0, 0.33f), IGraphics::CORNER_NONE, 0.0f); + CUIRect Background; + Overlay.VMargin(150.0f, &Background); + Background.HMargin(50.0f, &Background); + Background.Draw(ColorRGBA(0, 0, 0, 0.80f), IGraphics::CORNER_ALL, 5.0f); + + Background.Margin(10.0f, &Prompt); + + Prompt.VSplitMid(nullptr, &PromptBox); + + Prompt.HSplitTop(16.0f, &PromptBox, &Suggestions); + PromptBox.Draw(ColorRGBA(0, 0, 0, 0.75f), IGraphics::CORNER_ALL, 2.0f); + Suggestions.y += 6.0f; + + if(Ui()->DoClearableEditBox(&m_PromptInput, &PromptBox, 10.0f) || m_ResetFilterResults) + { + m_PromptSelectedIndex = 0; + m_vpFilteredPromptList.clear(); + if(m_ResetFilterResults && m_pLastAction) + { + m_vpFilteredPromptList.push_back(m_pLastAction); + } + for(auto *pQuickAction : m_vQuickActions) + { + if(m_PromptInput.IsEmpty() || FuzzyMatch(pQuickAction->Label(), m_PromptInput.GetString())) + { + bool Skip = false; + if(m_ResetFilterResults) + if(pQuickAction == m_pLastAction) + Skip = true; + if(!Skip) + m_vpFilteredPromptList.push_back(pQuickAction); + } + } + m_ResetFilterResults = false; + } + + s_ListBox.SetActive(!Ui()->IsPopupOpen()); + s_ListBox.DoStart(15.0f, m_vpFilteredPromptList.size(), 1, 5, m_PromptSelectedIndex, &Suggestions, false); + + for(size_t i = 0; i < m_vpFilteredPromptList.size(); i++) + { + const CListboxItem Item = s_ListBox.DoNextItem(m_vpFilteredPromptList[i], m_PromptSelectedIndex >= 0 && (size_t)m_PromptSelectedIndex == i); + if(!Item.m_Visible) + continue; + + CUIRect LabelColumn, DescColumn; + Item.m_Rect.VSplitLeft(5.0f, nullptr, &LabelColumn); + LabelColumn.VSplitLeft(100.0f, &LabelColumn, &DescColumn); + LabelColumn.VSplitRight(5.0f, &LabelColumn, nullptr); + + SLabelProperties Props; + Props.m_MaxWidth = LabelColumn.w; + Props.m_EllipsisAtEnd = true; + Ui()->DoLabel(&LabelColumn, m_vpFilteredPromptList[i]->Label(), 10.0f, TEXTALIGN_ML, Props); + + Props.m_MaxWidth = DescColumn.w; + ColorRGBA DescColor = TextRender()->DefaultTextColor(); + DescColor.a = Item.m_Selected ? 1.0f : 0.8f; + TextRender()->TextColor(DescColor); + Ui()->DoLabel(&DescColumn, m_vpFilteredPromptList[i]->Description(), 10.0f, TEXTALIGN_MR, Props); + TextRender()->TextColor(TextRender()->DefaultTextColor()); + } + + const int NewSelected = s_ListBox.DoEnd(); + if(m_PromptSelectedIndex != NewSelected) + { + m_PromptSelectedIndex = NewSelected; + } + + if(s_ListBox.WasItemActivated()) + { + if(m_PromptSelectedIndex >= 0) + { + const CQuickAction *pBtn = m_vpFilteredPromptList[m_PromptSelectedIndex]; + pBtn->Call(); + m_pLastAction = pBtn; + SetInactive(); + } + } +} diff --git a/src/game/editor/prompt.h b/src/game/editor/prompt.h new file mode 100644 index 00000000000..4b616ec983b --- /dev/null +++ b/src/game/editor/prompt.h @@ -0,0 +1,29 @@ +#ifndef GAME_EDITOR_PROMPT_H +#define GAME_EDITOR_PROMPT_H + +#include +#include +#include + +#include "component.h" + +class CPrompt : public CEditorComponent +{ + bool m_ResetFilterResults = true; + const CQuickAction *m_pLastAction = nullptr; + int m_PromptSelectedIndex = -1; + + std::vector m_vpFilteredPromptList; + std::vector m_vQuickActions; + CLineInputBuffered<512> m_PromptInput; + +public: + void OnInit(CEditor *pEditor) override; + bool OnInput(const IInput::CEvent &Event) override; + void OnRender(CUIRect _) override; + bool IsActive(); + void SetActive(); + void SetInactive(); +}; + +#endif diff --git a/src/game/editor/quick_action.h b/src/game/editor/quick_action.h new file mode 100644 index 00000000000..05efca84ea7 --- /dev/null +++ b/src/game/editor/quick_action.h @@ -0,0 +1,58 @@ +#ifndef GAME_EDITOR_QUICK_ACTION_H +#define GAME_EDITOR_QUICK_ACTION_H + +#include +#include + +typedef std::function FButtonClickCallback; +typedef std::function FButtonDisabledCallback; +typedef std::function FButtonActiveCallback; +typedef std::function FButtonColorCallback; + +class CQuickAction +{ +private: + const char *m_pLabel; + const char *m_pDescription; + + FButtonClickCallback m_pfnCallback; + FButtonDisabledCallback m_pfnDisabledCallback; + FButtonActiveCallback m_pfnActiveCallback; + FButtonColorCallback m_pfnColorCallback; + +public: + CQuickAction( + const char *pLabel, + const char *pDescription, + FButtonClickCallback pfnCallback, + FButtonDisabledCallback pfnDisabledCallback, + FButtonActiveCallback pfnActiveCallback, + FButtonColorCallback pfnColorCallback) : + m_pLabel(pLabel), + m_pDescription(pDescription), + m_pfnCallback(std::move(pfnCallback)), + m_pfnDisabledCallback(std::move(pfnDisabledCallback)), + m_pfnActiveCallback(std::move(pfnActiveCallback)), + m_pfnColorCallback(std::move(pfnColorCallback)) + { + } + + // code to run when the action is triggered + void Call() const { m_pfnCallback(); } + + // bool that indicates if the action can be performed not or not + bool Disabled() { return m_pfnDisabledCallback(); } + + // bool that indicates if the action is currently running + // only applies to actions that can be turned on or off like proof borders + bool Active() { return m_pfnActiveCallback(); } + + // color "enum" that represents the state of the quick actions button + // used as Checked argument for DoButton_Editor() + int Color() { return m_pfnColorCallback(); } + + const char *Label() const { return m_pLabel; } + const char *Description() const { return m_pDescription; } +}; + +#endif diff --git a/src/game/editor/quick_actions.cpp b/src/game/editor/quick_actions.cpp new file mode 100644 index 00000000000..b9ced6d5719 --- /dev/null +++ b/src/game/editor/quick_actions.cpp @@ -0,0 +1,20 @@ +#include "editor.h" + +#include "editor_actions.h" + +void CEditor::AddGroup() +{ + m_Map.NewGroup(); + m_SelectedGroup = m_Map.m_vpGroups.size() - 1; + m_EditorHistory.RecordAction(std::make_shared(this, m_SelectedGroup, false)); +} +void CEditor::AddTileLayer() +{ + std::shared_ptr pTileLayer = std::make_shared(this, m_Map.m_pGameLayer->m_Width, m_Map.m_pGameLayer->m_Height); + pTileLayer->m_pEditor = this; + m_Map.m_vpGroups[m_SelectedGroup]->AddLayer(pTileLayer); + int LayerIndex = m_Map.m_vpGroups[m_SelectedGroup]->m_vpLayers.size() - 1; + SelectLayer(LayerIndex); + m_Map.m_vpGroups[m_SelectedGroup]->m_Collapse = false; + m_EditorHistory.RecordAction(std::make_shared(this, m_SelectedGroup, LayerIndex)); +} diff --git a/src/game/editor/quick_actions.h b/src/game/editor/quick_actions.h new file mode 100644 index 00000000000..d581fd13021 --- /dev/null +++ b/src/game/editor/quick_actions.h @@ -0,0 +1,50 @@ +// This file can be included several times. + +#ifndef REGISTER_QUICK_ACTION +#define REGISTER_QUICK_ACTION(name, text, callback, disabled, active, button_color, description) +#endif + +#define ALWAYS_FALSE []() -> bool { return false; } +#define DEFAULT_BTN []() -> int { return -1; } + +REGISTER_QUICK_ACTION( + AddGroup, "Add group", [&]() { AddGroup(); }, ALWAYS_FALSE, ALWAYS_FALSE, DEFAULT_BTN, "Adds a new group") +REGISTER_QUICK_ACTION( + Refocus, "Refocus", [&]() { MapView()->Focus(); }, ALWAYS_FALSE, ALWAYS_FALSE, DEFAULT_BTN, "[HOME] Restore map focus") +REGISTER_QUICK_ACTION( + Proof, + "Proof", + [&]() { MapView()->ProofMode()->Toggle(); }, + ALWAYS_FALSE, + [&]() -> bool { return MapView()->ProofMode()->IsEnabled(); }, + DEFAULT_BTN, + "Toggles proof borders. These borders represent the area that a player can see with default zoom.") +REGISTER_QUICK_ACTION( + AddTileLayer, "Add tile layer", [&]() { AddTileLayer(); }, ALWAYS_FALSE, ALWAYS_FALSE, DEFAULT_BTN, "Creates a new tile layer.") +REGISTER_QUICK_ACTION( + SaveAs, + "Save As", + [&]() { InvokeFileDialog(IStorage::TYPE_SAVE, FILETYPE_MAP, "Save map", "Save As", "maps", true, CEditor::CallbackSaveMap, this); }, + ALWAYS_FALSE, + ALWAYS_FALSE, + DEFAULT_BTN, + "Saves the current map under a new name (ctrl+shift+s)") +REGISTER_QUICK_ACTION( + Envelopes, + "Envelopes", + [&]() { m_ActiveExtraEditor = m_ActiveExtraEditor == EXTRAEDITOR_ENVELOPES ? EXTRAEDITOR_NONE : EXTRAEDITOR_ENVELOPES; }, + ALWAYS_FALSE, + ALWAYS_FALSE, + [&]() -> int { return m_ShowPicker ? -1 : m_ActiveExtraEditor == EXTRAEDITOR_ENVELOPES; }, + "Toggles the envelope editor.") +REGISTER_QUICK_ACTION( + AddImage, + "Add Image", + [&]() { InvokeFileDialog(IStorage::TYPE_ALL, FILETYPE_IMG, "Add Image", "Add", "mapres", false, AddImage, this); }, + ALWAYS_FALSE, + ALWAYS_FALSE, + DEFAULT_BTN, + "Load a new image to use in the map") + +#undef ALWAYS_FALSE +#undef DEFAULT_BTN From 2c77aeef2baa94d6a269af531914ab89987214aa Mon Sep 17 00:00:00 2001 From: ChillerDragon Date: Mon, 5 Aug 2024 15:09:02 +0800 Subject: [PATCH 17/30] Add quick action to pick image for selected layer --- src/game/editor/editor.h | 2 ++ src/game/editor/prompt.cpp | 5 ++++- src/game/editor/quick_actions.cpp | 35 +++++++++++++++++++++++++++++++ src/game/editor/quick_actions.h | 8 +++++++ 4 files changed, 49 insertions(+), 1 deletion(-) diff --git a/src/game/editor/editor.h b/src/game/editor/editor.h index 8b5212a1a98..5c69cadaf46 100644 --- a/src/game/editor/editor.h +++ b/src/game/editor/editor.h @@ -325,6 +325,8 @@ class CEditor : public IEditor void AddGroup(); void AddTileLayer(); + void LayerSelectImage(); + bool IsNonGameTileLayerSelected() const; #define REGISTER_QUICK_ACTION(name, text, callback, disabled, active, button_color, description) CQuickAction m_QuickAction##name; #include #undef REGISTER_QUICK_ACTION diff --git a/src/game/editor/prompt.cpp b/src/game/editor/prompt.cpp index 213466bf5bc..4e08852c1e3 100644 --- a/src/game/editor/prompt.cpp +++ b/src/game/editor/prompt.cpp @@ -107,6 +107,9 @@ void CPrompt::OnRender(CUIRect _) } for(auto *pQuickAction : m_vQuickActions) { + if(pQuickAction->Disabled()) + continue; + if(m_PromptInput.IsEmpty() || FuzzyMatch(pQuickAction->Label(), m_PromptInput.GetString())) { bool Skip = false; @@ -158,9 +161,9 @@ void CPrompt::OnRender(CUIRect _) if(m_PromptSelectedIndex >= 0) { const CQuickAction *pBtn = m_vpFilteredPromptList[m_PromptSelectedIndex]; + SetInactive(); pBtn->Call(); m_pLastAction = pBtn; - SetInactive(); } } } diff --git a/src/game/editor/quick_actions.cpp b/src/game/editor/quick_actions.cpp index b9ced6d5719..80b07c787de 100644 --- a/src/game/editor/quick_actions.cpp +++ b/src/game/editor/quick_actions.cpp @@ -1,3 +1,5 @@ +#include + #include "editor.h" #include "editor_actions.h" @@ -18,3 +20,36 @@ void CEditor::AddTileLayer() m_Map.m_vpGroups[m_SelectedGroup]->m_Collapse = false; m_EditorHistory.RecordAction(std::make_shared(this, m_SelectedGroup, LayerIndex)); } + +bool CEditor::IsNonGameTileLayerSelected() const +{ + std::shared_ptr pLayer = GetSelectedLayer(0); + if(!pLayer) + return false; + if(pLayer->m_Type != LAYERTYPE_TILES) + return false; + if( + pLayer == m_Map.m_pGameLayer || + pLayer == m_Map.m_pFrontLayer || + pLayer == m_Map.m_pSwitchLayer || + pLayer == m_Map.m_pTeleLayer || + pLayer == m_Map.m_pSpeedupLayer || + pLayer == m_Map.m_pTuneLayer) + return false; + + return true; +} + +void CEditor::LayerSelectImage() +{ + if(!IsNonGameTileLayerSelected()) + return; + + std::shared_ptr pLayer = GetSelectedLayer(0); + std::shared_ptr pTiles = std::static_pointer_cast(pLayer); + + static SLayerPopupContext s_LayerPopupContext = {}; + s_LayerPopupContext.m_pEditor = this; + Ui()->DoPopupMenu(&s_LayerPopupContext, Ui()->MouseX(), Ui()->MouseY(), 120, 270, &s_LayerPopupContext, PopupLayer); + PopupSelectImageInvoke(pTiles->m_Image, Ui()->MouseX(), Ui()->MouseY()); +} diff --git a/src/game/editor/quick_actions.h b/src/game/editor/quick_actions.h index d581fd13021..8264b043245 100644 --- a/src/game/editor/quick_actions.h +++ b/src/game/editor/quick_actions.h @@ -45,6 +45,14 @@ REGISTER_QUICK_ACTION( ALWAYS_FALSE, DEFAULT_BTN, "Load a new image to use in the map") +REGISTER_QUICK_ACTION( + LayerPropAddImage, + "Layer: Add Image", + [&]() { LayerSelectImage(); }, + [&]() -> bool { return !IsNonGameTileLayerSelected(); }, + ALWAYS_FALSE, + DEFAULT_BTN, + "Pick mapres image for currently selected layer") #undef ALWAYS_FALSE #undef DEFAULT_BTN From e20250cd6504e384d53bf256f81b6e740ed0e4b2 Mon Sep 17 00:00:00 2001 From: ChillerDragon Date: Sun, 1 Sep 2024 08:15:58 +0800 Subject: [PATCH 18/30] Add quick action "Load Current Map" --- src/game/editor/popups.cpp | 12 ++---------- src/game/editor/quick_actions.h | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/game/editor/popups.cpp b/src/game/editor/popups.cpp index 45844b64a0d..0b070e301bb 100644 --- a/src/game/editor/popups.cpp +++ b/src/game/editor/popups.cpp @@ -68,17 +68,9 @@ CUi::EPopupMenuFunctionResult CEditor::PopupMenuFile(void *pContext, CUIRect Vie View.HSplitTop(2.0f, nullptr, &View); View.HSplitTop(12.0f, &Slot, &View); - if(pEditor->DoButton_MenuItem(&s_OpenCurrentMapButton, "Load Current Map", 0, &Slot, 0, "Opens the current in game map for editing (ctrl+alt+l)")) + if(pEditor->DoButton_MenuItem(&s_OpenCurrentMapButton, pEditor->m_QuickActionLoadCurrentMap.Label(), 0, &Slot, 0, pEditor->m_QuickActionLoadCurrentMap.Description())) { - if(pEditor->HasUnsavedData()) - { - pEditor->m_PopupEventType = POPEVENT_LOADCURRENT; - pEditor->m_PopupEventActivated = true; - } - else - { - pEditor->LoadCurrentMap(); - } + pEditor->m_QuickActionLoadCurrentMap.Call(); return CUi::POPUP_CLOSE_CURRENT; } diff --git a/src/game/editor/quick_actions.h b/src/game/editor/quick_actions.h index 8264b043245..d89dee77f0e 100644 --- a/src/game/editor/quick_actions.h +++ b/src/game/editor/quick_actions.h @@ -29,6 +29,24 @@ REGISTER_QUICK_ACTION( ALWAYS_FALSE, DEFAULT_BTN, "Saves the current map under a new name (ctrl+shift+s)") +REGISTER_QUICK_ACTION( + LoadCurrentMap, + "Load Current Map", + [&]() { + if(HasUnsavedData()) + { + m_PopupEventType = POPEVENT_LOADCURRENT; + m_PopupEventActivated = true; + } + else + { + LoadCurrentMap(); + } + }, + ALWAYS_FALSE, + ALWAYS_FALSE, + DEFAULT_BTN, + "Opens the current in game map for editing (ctrl+alt+l)") REGISTER_QUICK_ACTION( Envelopes, "Envelopes", From ed49fef917d5b035b64175e04c52c859024842ac Mon Sep 17 00:00:00 2001 From: ChillerDragon Date: Sun, 1 Sep 2024 08:43:13 +0800 Subject: [PATCH 19/30] Add quick actions for Show Info Off/Dec/Hex --- src/game/editor/popups.cpp | 18 +++++++++--------- src/game/editor/quick_action.h | 11 +++++++++++ src/game/editor/quick_actions.h | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 9 deletions(-) diff --git a/src/game/editor/popups.cpp b/src/game/editor/popups.cpp index 45844b64a0d..86929cb01a3 100644 --- a/src/game/editor/popups.cpp +++ b/src/game/editor/popups.cpp @@ -314,20 +314,20 @@ CUi::EPopupMenuFunctionResult CEditor::PopupMenuSettings(void *pContext, CUIRect static int s_ButtonOff = 0; static int s_ButtonDec = 0; static int s_ButtonHex = 0; - if(pEditor->DoButton_Ex(&s_ButtonOff, "Off", pEditor->m_ShowTileInfo == SHOW_TILE_OFF, &Off, 0, "Do not show tile information", IGraphics::CORNER_L)) + CQuickAction *pAction = &pEditor->m_QuickActionShowInfoOff; + if(pEditor->DoButton_Ex(&s_ButtonOff, pAction->LabelShort(), pAction->Active(), &Off, 0, pAction->Description(), IGraphics::CORNER_L)) { - pEditor->m_ShowTileInfo = SHOW_TILE_OFF; - pEditor->m_ShowEnvelopePreview = SHOWENV_NONE; + pAction->Call(); } - if(pEditor->DoButton_Ex(&s_ButtonDec, "Dec", pEditor->m_ShowTileInfo == SHOW_TILE_DECIMAL, &Dec, 0, "[ctrl+i] Show tile information", IGraphics::CORNER_NONE)) + pAction = &pEditor->m_QuickActionShowInfoDec; + if(pEditor->DoButton_Ex(&s_ButtonDec, pAction->LabelShort(), pAction->Active(), &Dec, 0, pAction->Description(), IGraphics::CORNER_NONE)) { - pEditor->m_ShowTileInfo = SHOW_TILE_DECIMAL; - pEditor->m_ShowEnvelopePreview = SHOWENV_NONE; + pAction->Call(); } - if(pEditor->DoButton_Ex(&s_ButtonHex, "Hex", pEditor->m_ShowTileInfo == SHOW_TILE_HEXADECIMAL, &Hex, 0, "[ctrl+shift+i] Show tile information in hexadecimal", IGraphics::CORNER_R)) + pAction = &pEditor->m_QuickActionShowInfoHex; + if(pEditor->DoButton_Ex(&s_ButtonHex, pAction->LabelShort(), pAction->Active(), &Hex, 0, pAction->Description(), IGraphics::CORNER_R)) { - pEditor->m_ShowTileInfo = SHOW_TILE_HEXADECIMAL; - pEditor->m_ShowEnvelopePreview = SHOWENV_NONE; + pAction->Call(); } } diff --git a/src/game/editor/quick_action.h b/src/game/editor/quick_action.h index 05efca84ea7..124713643dd 100644 --- a/src/game/editor/quick_action.h +++ b/src/game/editor/quick_action.h @@ -52,6 +52,17 @@ class CQuickAction int Color() { return m_pfnColorCallback(); } const char *Label() const { return m_pLabel; } + + // skips to the part of the label after the first colon + // useful for buttons that only show the state + const char *LabelShort() const + { + const char *pShort = str_find(m_pLabel, ": "); + if(!pShort) + return m_pLabel; + return pShort + 2; + } + const char *Description() const { return m_pDescription; } }; diff --git a/src/game/editor/quick_actions.h b/src/game/editor/quick_actions.h index 8264b043245..ab1d038d17f 100644 --- a/src/game/editor/quick_actions.h +++ b/src/game/editor/quick_actions.h @@ -53,6 +53,39 @@ REGISTER_QUICK_ACTION( ALWAYS_FALSE, DEFAULT_BTN, "Pick mapres image for currently selected layer") +REGISTER_QUICK_ACTION( + ShowInfoOff, + "Show Info: Off", + [&]() { + m_ShowTileInfo = SHOW_TILE_OFF; + m_ShowEnvelopePreview = SHOWENV_NONE; + }, + ALWAYS_FALSE, + [&]() -> bool { return m_ShowTileInfo == SHOW_TILE_OFF; }, + DEFAULT_BTN, + "Do not show tile information") +REGISTER_QUICK_ACTION( + ShowInfoDec, + "Show Info: Dec", + [&]() { + m_ShowTileInfo = SHOW_TILE_DECIMAL; + m_ShowEnvelopePreview = SHOWENV_NONE; + }, + ALWAYS_FALSE, + [&]() -> bool { return m_ShowTileInfo == SHOW_TILE_DECIMAL; }, + DEFAULT_BTN, + "[ctrl+i] Show tile information") +REGISTER_QUICK_ACTION( + ShowInfoHex, + "Show Info: Hex", + [&]() { + m_ShowTileInfo = SHOW_TILE_HEXADECIMAL; + m_ShowEnvelopePreview = SHOWENV_NONE; + }, + ALWAYS_FALSE, + [&]() -> bool { return m_ShowTileInfo == SHOW_TILE_HEXADECIMAL; }, + DEFAULT_BTN, + "[ctrl+shift+i] Show tile information in hexadecimal") #undef ALWAYS_FALSE #undef DEFAULT_BTN From daad41fbd747cdb8cd7a59f5ab2c2b7854ba30dc Mon Sep 17 00:00:00 2001 From: ChillerDragon Date: Sun, 1 Sep 2024 10:38:33 +0800 Subject: [PATCH 20/30] Fix editor prompt suggesting disabled last action The editor prompt always has as a first entry the last action that ran. But this entry should not show up if that action is currently disabled. --- src/game/editor/prompt.cpp | 4 ++-- src/game/editor/prompt.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/game/editor/prompt.cpp b/src/game/editor/prompt.cpp index 4e08852c1e3..a72db4671a2 100644 --- a/src/game/editor/prompt.cpp +++ b/src/game/editor/prompt.cpp @@ -101,7 +101,7 @@ void CPrompt::OnRender(CUIRect _) { m_PromptSelectedIndex = 0; m_vpFilteredPromptList.clear(); - if(m_ResetFilterResults && m_pLastAction) + if(m_ResetFilterResults && m_pLastAction && !m_pLastAction->Disabled()) { m_vpFilteredPromptList.push_back(m_pLastAction); } @@ -160,7 +160,7 @@ void CPrompt::OnRender(CUIRect _) { if(m_PromptSelectedIndex >= 0) { - const CQuickAction *pBtn = m_vpFilteredPromptList[m_PromptSelectedIndex]; + CQuickAction *pBtn = m_vpFilteredPromptList[m_PromptSelectedIndex]; SetInactive(); pBtn->Call(); m_pLastAction = pBtn; diff --git a/src/game/editor/prompt.h b/src/game/editor/prompt.h index 4b616ec983b..2d873e580c8 100644 --- a/src/game/editor/prompt.h +++ b/src/game/editor/prompt.h @@ -10,10 +10,10 @@ class CPrompt : public CEditorComponent { bool m_ResetFilterResults = true; - const CQuickAction *m_pLastAction = nullptr; + CQuickAction *m_pLastAction = nullptr; int m_PromptSelectedIndex = -1; - std::vector m_vpFilteredPromptList; + std::vector m_vpFilteredPromptList; std::vector m_vQuickActions; CLineInputBuffered<512> m_PromptInput; From e1cb617c42cbf0735ada79b8bb41237ddc0f4177 Mon Sep 17 00:00:00 2001 From: ChillerDragon Date: Sun, 1 Sep 2024 10:06:29 +0800 Subject: [PATCH 21/30] Add quick actions for game tiles --- CMakeLists.txt | 1 + src/game/editor/editor.h | 3 + src/game/editor/enums.h | 36 +++ src/game/editor/mapitems/layer_tiles.cpp | 350 ++++++++++++----------- src/game/editor/mapitems/layer_tiles.h | 3 + src/game/editor/quick_actions.cpp | 16 ++ src/game/editor/quick_actions.h | 104 +++++++ 7 files changed, 340 insertions(+), 173 deletions(-) create mode 100644 src/game/editor/enums.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 99cfe65100a..0fff61f166f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2462,6 +2462,7 @@ if(CLIENT) editor_trackers.cpp editor_trackers.h editor_ui.h + enums.h explanations.cpp layer_selector.cpp layer_selector.h diff --git a/src/game/editor/editor.h b/src/game/editor/editor.h index 5c69cadaf46..6206cea25f3 100644 --- a/src/game/editor/editor.h +++ b/src/game/editor/editor.h @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -323,6 +324,8 @@ class CEditor : public IEditor const CMapView *MapView() const { return &m_MapView; } CLayerSelector *LayerSelector() { return &m_LayerSelector; } + void FillGameTiles(EGameTileOp FillTile) const; + bool CanFillGameTiles() const; void AddGroup(); void AddTileLayer(); void LayerSelectImage(); diff --git a/src/game/editor/enums.h b/src/game/editor/enums.h new file mode 100644 index 00000000000..d14679b95d2 --- /dev/null +++ b/src/game/editor/enums.h @@ -0,0 +1,36 @@ +#ifndef GAME_EDITOR_ENUMS_H +#define GAME_EDITOR_ENUMS_H + +constexpr const char *g_apGametileOpNames[] = { + "Air", + "Hookable", + "Death", + "Unhookable", + "Hookthrough", + "Freeze", + "Unfreeze", + "Deep Freeze", + "Deep Unfreeze", + "Blue Check-Tele", + "Red Check-Tele", + "Live Freeze", + "Live Unfreeze", +}; +enum class EGameTileOp +{ + AIR, + HOOKABLE, + DEATH, + UNHOOKABLE, + HOOKTHROUGH, + FREEZE, + UNFREEZE, + DEEP_FREEZE, + DEEP_UNFREEZE, + BLUE_CHECK_TELE, + RED_CHECK_TELE, + LIVE_FREEZE, + LIVE_UNFREEZE, +}; + +#endif diff --git a/src/game/editor/mapitems/layer_tiles.cpp b/src/game/editor/mapitems/layer_tiles.cpp index 380af7d8fc5..665a0fec97b 100644 --- a/src/game/editor/mapitems/layer_tiles.cpp +++ b/src/game/editor/mapitems/layer_tiles.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -693,93 +694,126 @@ void CLayerTiles::ShowInfo() Graphics()->MapScreen(ScreenX0, ScreenY0, ScreenX1, ScreenY1); } -CUi::EPopupMenuFunctionResult CLayerTiles::RenderProperties(CUIRect *pToolBox) +void CLayerTiles::FillGameTiles(EGameTileOp Fill) { - CUIRect Button; - - const bool EntitiesLayer = IsEntitiesLayer(); + if(!CanFillGameTiles()) + return; std::shared_ptr pGroup = m_pEditor->m_Map.m_vpGroups[m_pEditor->m_SelectedGroup]; - // Game tiles can only be constructed if the layer is relative to the game layer - if(!EntitiesLayer && !(pGroup->m_OffsetX % 32) && !(pGroup->m_OffsetY % 32) && pGroup->m_ParallaxX == 100 && pGroup->m_ParallaxY == 100) + int Result = (int)Fill; + switch(Fill) { - pToolBox->HSplitBottom(12.0f, pToolBox, &Button); - static int s_GameTilesButton = 0; - if(m_pEditor->DoButton_Editor(&s_GameTilesButton, "Game tiles", 0, &Button, 0, "Constructs game tiles from this layer")) - m_pEditor->PopupSelectGametileOpInvoke(m_pEditor->Ui()->MouseX(), m_pEditor->Ui()->MouseY()); - const int Selected = m_pEditor->PopupSelectGameTileOpResult(); - int Result = Selected; - switch(Selected) + case EGameTileOp::HOOKTHROUGH: + Result = TILE_THROUGH_CUT; + break; + case EGameTileOp::FREEZE: + Result = TILE_FREEZE; + break; + case EGameTileOp::UNFREEZE: + Result = TILE_UNFREEZE; + break; + case EGameTileOp::DEEP_FREEZE: + Result = TILE_DFREEZE; + break; + case EGameTileOp::DEEP_UNFREEZE: + Result = TILE_DUNFREEZE; + break; + case EGameTileOp::BLUE_CHECK_TELE: + Result = TILE_TELECHECKIN; + break; + case EGameTileOp::RED_CHECK_TELE: + Result = TILE_TELECHECKINEVIL; + break; + case EGameTileOp::LIVE_FREEZE: + Result = TILE_LFREEZE; + break; + case EGameTileOp::LIVE_UNFREEZE: + Result = TILE_LUNFREEZE; + break; + default: + break; + } + if(Result > -1) + { + const int OffsetX = -pGroup->m_OffsetX / 32; + const int OffsetY = -pGroup->m_OffsetY / 32; + + std::vector> vpActions; + std::shared_ptr pGLayer = m_pEditor->m_Map.m_pGameLayer; + int GameLayerIndex = std::find(m_pEditor->m_Map.m_pGameGroup->m_vpLayers.begin(), m_pEditor->m_Map.m_pGameGroup->m_vpLayers.end(), pGLayer) - m_pEditor->m_Map.m_pGameGroup->m_vpLayers.begin(); + + if(Result != TILE_TELECHECKIN && Result != TILE_TELECHECKINEVIL) { - case 4: - Result = TILE_THROUGH_CUT; - break; - case 5: - Result = TILE_FREEZE; - break; - case 6: - Result = TILE_UNFREEZE; - break; - case 7: - Result = TILE_DFREEZE; - break; - case 8: - Result = TILE_DUNFREEZE; - break; - case 9: - Result = TILE_TELECHECKIN; - break; - case 10: - Result = TILE_TELECHECKINEVIL; - break; - case 11: - Result = TILE_LFREEZE; - break; - case 12: - Result = TILE_LUNFREEZE; - break; - default: - break; + if(pGLayer->m_Width < m_Width + OffsetX || pGLayer->m_Height < m_Height + OffsetY) + { + std::map> savedLayers; + savedLayers[LAYERTYPE_TILES] = pGLayer->Duplicate(); + savedLayers[LAYERTYPE_GAME] = savedLayers[LAYERTYPE_TILES]; + + int PrevW = pGLayer->m_Width; + int PrevH = pGLayer->m_Height; + const int NewW = pGLayer->m_Width < m_Width + OffsetX ? m_Width + OffsetX : pGLayer->m_Width; + const int NewH = pGLayer->m_Height < m_Height + OffsetY ? m_Height + OffsetY : pGLayer->m_Height; + pGLayer->Resize(NewW, NewH); + vpActions.push_back(std::make_shared(m_pEditor, m_pEditor->m_SelectedGroup, GameLayerIndex, ETilesProp::PROP_WIDTH, PrevW, NewW)); + const std::shared_ptr &Action1 = std::static_pointer_cast(vpActions[vpActions.size() - 1]); + vpActions.push_back(std::make_shared(m_pEditor, m_pEditor->m_SelectedGroup, GameLayerIndex, ETilesProp::PROP_HEIGHT, PrevH, NewH)); + const std::shared_ptr &Action2 = std::static_pointer_cast(vpActions[vpActions.size() - 1]); + + Action1->SetSavedLayers(savedLayers); + Action2->SetSavedLayers(savedLayers); + } + + int Changes = 0; + for(int y = OffsetY < 0 ? -OffsetY : 0; y < m_Height; y++) + { + for(int x = OffsetX < 0 ? -OffsetX : 0; x < m_Width; x++) + { + if(GetTile(x, y).m_Index) + { + const CTile ResultTile = {(unsigned char)Result}; + pGLayer->SetTile(x + OffsetX, y + OffsetY, ResultTile); + Changes++; + } + } + } + + vpActions.push_back(std::make_shared(m_pEditor, m_pEditor->m_SelectedGroup)); + char aDisplay[256]; + str_format(aDisplay, sizeof(aDisplay), "Construct '%s' game tiles (x%d)", g_apGametileOpNames[(int)Fill], Changes); + m_pEditor->m_EditorHistory.RecordAction(std::make_shared(m_pEditor, vpActions, aDisplay, true)); } - if(Result > -1) + else { - const int OffsetX = -pGroup->m_OffsetX / 32; - const int OffsetY = -pGroup->m_OffsetY / 32; - - static const char *s_apGametileOpNames[] = { - "Air", - "Hookable", - "Death", - "Unhookable", - "Hookthrough", - "Freeze", - "Unfreeze", - "Deep Freeze", - "Deep Unfreeze", - "Blue Check-Tele", - "Red Check-Tele", - "Live Freeze", - "Live Unfreeze", - }; + if(!m_pEditor->m_Map.m_pTeleLayer) + { + std::shared_ptr pLayer = std::make_shared(m_pEditor, m_Width, m_Height); + m_pEditor->m_Map.MakeTeleLayer(pLayer); + m_pEditor->m_Map.m_pGameGroup->AddLayer(pLayer); - std::vector> vpActions; - std::shared_ptr pGLayer = m_pEditor->m_Map.m_pGameLayer; - int GameLayerIndex = std::find(m_pEditor->m_Map.m_pGameGroup->m_vpLayers.begin(), m_pEditor->m_Map.m_pGameGroup->m_vpLayers.end(), pGLayer) - m_pEditor->m_Map.m_pGameGroup->m_vpLayers.begin(); + vpActions.push_back(std::make_shared(m_pEditor, m_pEditor->m_SelectedGroup, m_pEditor->m_Map.m_pGameGroup->m_vpLayers.size() - 1)); - if(Result != TILE_TELECHECKIN && Result != TILE_TELECHECKINEVIL) - { - if(pGLayer->m_Width < m_Width + OffsetX || pGLayer->m_Height < m_Height + OffsetY) + if(m_Width != pGLayer->m_Width || m_Height > pGLayer->m_Height) { std::map> savedLayers; savedLayers[LAYERTYPE_TILES] = pGLayer->Duplicate(); savedLayers[LAYERTYPE_GAME] = savedLayers[LAYERTYPE_TILES]; + int NewW = pGLayer->m_Width; + int NewH = pGLayer->m_Height; + if(m_Width > pGLayer->m_Width) + { + NewW = m_Width; + } + if(m_Height > pGLayer->m_Height) + { + NewH = m_Height; + } + int PrevW = pGLayer->m_Width; int PrevH = pGLayer->m_Height; - const int NewW = pGLayer->m_Width < m_Width + OffsetX ? m_Width + OffsetX : pGLayer->m_Width; - const int NewH = pGLayer->m_Height < m_Height + OffsetY ? m_Height + OffsetY : pGLayer->m_Height; - pGLayer->Resize(NewW, NewH); + pLayer->Resize(NewW, NewH); vpActions.push_back(std::make_shared(m_pEditor, m_pEditor->m_SelectedGroup, GameLayerIndex, ETilesProp::PROP_WIDTH, PrevW, NewW)); const std::shared_ptr &Action1 = std::static_pointer_cast(vpActions[vpActions.size() - 1]); vpActions.push_back(std::make_shared(m_pEditor, m_pEditor->m_SelectedGroup, GameLayerIndex, ETilesProp::PROP_HEIGHT, PrevH, NewH)); @@ -788,124 +822,94 @@ CUi::EPopupMenuFunctionResult CLayerTiles::RenderProperties(CUIRect *pToolBox) Action1->SetSavedLayers(savedLayers); Action2->SetSavedLayers(savedLayers); } + } - int Changes = 0; - for(int y = OffsetY < 0 ? -OffsetY : 0; y < m_Height; y++) - { - for(int x = OffsetX < 0 ? -OffsetX : 0; x < m_Width; x++) - { - if(GetTile(x, y).m_Index) - { - const CTile ResultTile = {(unsigned char)Result}; - pGLayer->SetTile(x + OffsetX, y + OffsetY, ResultTile); - Changes++; - } - } - } + std::shared_ptr pTLayer = m_pEditor->m_Map.m_pTeleLayer; + int TeleLayerIndex = std::find(m_pEditor->m_Map.m_pGameGroup->m_vpLayers.begin(), m_pEditor->m_Map.m_pGameGroup->m_vpLayers.end(), pTLayer) - m_pEditor->m_Map.m_pGameGroup->m_vpLayers.begin(); - vpActions.push_back(std::make_shared(m_pEditor, m_pEditor->m_SelectedGroup)); - char aDisplay[256]; - str_format(aDisplay, sizeof(aDisplay), "Construct '%s' game tiles (x%d)", s_apGametileOpNames[Selected], Changes); - m_pEditor->m_EditorHistory.RecordAction(std::make_shared(m_pEditor, vpActions, aDisplay, true)); + if(pTLayer->m_Width < m_Width + OffsetX || pTLayer->m_Height < m_Height + OffsetY) + { + std::map> savedLayers; + savedLayers[LAYERTYPE_TILES] = pTLayer->Duplicate(); + savedLayers[LAYERTYPE_TELE] = savedLayers[LAYERTYPE_TILES]; + + int PrevW = pTLayer->m_Width; + int PrevH = pTLayer->m_Height; + int NewW = pTLayer->m_Width < m_Width + OffsetX ? m_Width + OffsetX : pTLayer->m_Width; + int NewH = pTLayer->m_Height < m_Height + OffsetY ? m_Height + OffsetY : pTLayer->m_Height; + pTLayer->Resize(NewW, NewH); + std::shared_ptr Action1, Action2; + vpActions.push_back(Action1 = std::make_shared(m_pEditor, m_pEditor->m_SelectedGroup, TeleLayerIndex, ETilesProp::PROP_WIDTH, PrevW, NewW)); + vpActions.push_back(Action2 = std::make_shared(m_pEditor, m_pEditor->m_SelectedGroup, TeleLayerIndex, ETilesProp::PROP_HEIGHT, PrevH, NewH)); + + Action1->SetSavedLayers(savedLayers); + Action2->SetSavedLayers(savedLayers); } - else + + int Changes = 0; + for(int y = OffsetY < 0 ? -OffsetY : 0; y < m_Height; y++) { - if(!m_pEditor->m_Map.m_pTeleLayer) + for(int x = OffsetX < 0 ? -OffsetX : 0; x < m_Width; x++) { - std::shared_ptr pLayer = std::make_shared(m_pEditor, m_Width, m_Height); - m_pEditor->m_Map.MakeTeleLayer(pLayer); - m_pEditor->m_Map.m_pGameGroup->AddLayer(pLayer); - - vpActions.push_back(std::make_shared(m_pEditor, m_pEditor->m_SelectedGroup, m_pEditor->m_Map.m_pGameGroup->m_vpLayers.size() - 1)); - - if(m_Width != pGLayer->m_Width || m_Height > pGLayer->m_Height) + if(GetTile(x, y).m_Index) { - std::map> savedLayers; - savedLayers[LAYERTYPE_TILES] = pGLayer->Duplicate(); - savedLayers[LAYERTYPE_GAME] = savedLayers[LAYERTYPE_TILES]; - - int NewW = pGLayer->m_Width; - int NewH = pGLayer->m_Height; - if(m_Width > pGLayer->m_Width) - { - NewW = m_Width; - } - if(m_Height > pGLayer->m_Height) - { - NewH = m_Height; - } - - int PrevW = pGLayer->m_Width; - int PrevH = pGLayer->m_Height; - pLayer->Resize(NewW, NewH); - vpActions.push_back(std::make_shared(m_pEditor, m_pEditor->m_SelectedGroup, GameLayerIndex, ETilesProp::PROP_WIDTH, PrevW, NewW)); - const std::shared_ptr &Action1 = std::static_pointer_cast(vpActions[vpActions.size() - 1]); - vpActions.push_back(std::make_shared(m_pEditor, m_pEditor->m_SelectedGroup, GameLayerIndex, ETilesProp::PROP_HEIGHT, PrevH, NewH)); - const std::shared_ptr &Action2 = std::static_pointer_cast(vpActions[vpActions.size() - 1]); - - Action1->SetSavedLayers(savedLayers); - Action2->SetSavedLayers(savedLayers); - } - } + auto TileIndex = (y + OffsetY) * pTLayer->m_Width + x + OffsetX; + Changes++; - std::shared_ptr pTLayer = m_pEditor->m_Map.m_pTeleLayer; - int TeleLayerIndex = std::find(m_pEditor->m_Map.m_pGameGroup->m_vpLayers.begin(), m_pEditor->m_Map.m_pGameGroup->m_vpLayers.end(), pTLayer) - m_pEditor->m_Map.m_pGameGroup->m_vpLayers.begin(); + STeleTileStateChange::SData Previous{ + pTLayer->m_pTeleTile[TileIndex].m_Number, + pTLayer->m_pTeleTile[TileIndex].m_Type, + pTLayer->m_pTiles[TileIndex].m_Index}; - if(pTLayer->m_Width < m_Width + OffsetX || pTLayer->m_Height < m_Height + OffsetY) - { - std::map> savedLayers; - savedLayers[LAYERTYPE_TILES] = pTLayer->Duplicate(); - savedLayers[LAYERTYPE_TELE] = savedLayers[LAYERTYPE_TILES]; - - int PrevW = pTLayer->m_Width; - int PrevH = pTLayer->m_Height; - int NewW = pTLayer->m_Width < m_Width + OffsetX ? m_Width + OffsetX : pTLayer->m_Width; - int NewH = pTLayer->m_Height < m_Height + OffsetY ? m_Height + OffsetY : pTLayer->m_Height; - pTLayer->Resize(NewW, NewH); - std::shared_ptr Action1, Action2; - vpActions.push_back(Action1 = std::make_shared(m_pEditor, m_pEditor->m_SelectedGroup, TeleLayerIndex, ETilesProp::PROP_WIDTH, PrevW, NewW)); - vpActions.push_back(Action2 = std::make_shared(m_pEditor, m_pEditor->m_SelectedGroup, TeleLayerIndex, ETilesProp::PROP_HEIGHT, PrevH, NewH)); + pTLayer->m_pTiles[TileIndex].m_Index = TILE_AIR + Result; + pTLayer->m_pTeleTile[TileIndex].m_Number = 1; + pTLayer->m_pTeleTile[TileIndex].m_Type = TILE_AIR + Result; - Action1->SetSavedLayers(savedLayers); - Action2->SetSavedLayers(savedLayers); - } + STeleTileStateChange::SData Current{ + pTLayer->m_pTeleTile[TileIndex].m_Number, + pTLayer->m_pTeleTile[TileIndex].m_Type, + pTLayer->m_pTiles[TileIndex].m_Index}; - int Changes = 0; - for(int y = OffsetY < 0 ? -OffsetY : 0; y < m_Height; y++) - { - for(int x = OffsetX < 0 ? -OffsetX : 0; x < m_Width; x++) - { - if(GetTile(x, y).m_Index) - { - auto TileIndex = (y + OffsetY) * pTLayer->m_Width + x + OffsetX; - Changes++; - - STeleTileStateChange::SData Previous{ - pTLayer->m_pTeleTile[TileIndex].m_Number, - pTLayer->m_pTeleTile[TileIndex].m_Type, - pTLayer->m_pTiles[TileIndex].m_Index}; - - pTLayer->m_pTiles[TileIndex].m_Index = TILE_AIR + Result; - pTLayer->m_pTeleTile[TileIndex].m_Number = 1; - pTLayer->m_pTeleTile[TileIndex].m_Type = TILE_AIR + Result; - - STeleTileStateChange::SData Current{ - pTLayer->m_pTeleTile[TileIndex].m_Number, - pTLayer->m_pTeleTile[TileIndex].m_Type, - pTLayer->m_pTiles[TileIndex].m_Index}; - - pTLayer->RecordStateChange(x, y, Previous, Current); - } + pTLayer->RecordStateChange(x, y, Previous, Current); } } - - vpActions.push_back(std::make_shared(m_pEditor, m_pEditor->m_SelectedGroup)); - char aDisplay[256]; - str_format(aDisplay, sizeof(aDisplay), "Construct 'tele' game tiles (x%d)", Changes); - m_pEditor->m_EditorHistory.RecordAction(std::make_shared(m_pEditor, vpActions, aDisplay, true)); } + + vpActions.push_back(std::make_shared(m_pEditor, m_pEditor->m_SelectedGroup)); + char aDisplay[256]; + str_format(aDisplay, sizeof(aDisplay), "Construct 'tele' game tiles (x%d)", Changes); + m_pEditor->m_EditorHistory.RecordAction(std::make_shared(m_pEditor, vpActions, aDisplay, true)); } } +} + +bool CLayerTiles::CanFillGameTiles() const +{ + const bool EntitiesLayer = IsEntitiesLayer(); + if(EntitiesLayer) + return false; + + std::shared_ptr pGroup = m_pEditor->m_Map.m_vpGroups[m_pEditor->m_SelectedGroup]; + + // Game tiles can only be constructed if the layer is relative to the game layer + return !(pGroup->m_OffsetX % 32) && !(pGroup->m_OffsetY % 32) && pGroup->m_ParallaxX == 100 && pGroup->m_ParallaxY == 100; +} + +CUi::EPopupMenuFunctionResult CLayerTiles::RenderProperties(CUIRect *pToolBox) +{ + CUIRect Button; + + const bool EntitiesLayer = IsEntitiesLayer(); + + if(CanFillGameTiles()) + { + pToolBox->HSplitBottom(12.0f, pToolBox, &Button); + static int s_GameTilesButton = 0; + if(m_pEditor->DoButton_Editor(&s_GameTilesButton, "Game tiles", 0, &Button, 0, "Constructs game tiles from this layer")) + m_pEditor->PopupSelectGametileOpInvoke(m_pEditor->Ui()->MouseX(), m_pEditor->Ui()->MouseY()); + const int Selected = m_pEditor->PopupSelectGameTileOpResult(); + FillGameTiles((EGameTileOp)Selected); + } if(m_pEditor->m_Map.m_pGameLayer.get() != this) { diff --git a/src/game/editor/mapitems/layer_tiles.h b/src/game/editor/mapitems/layer_tiles.h index f5789a8984b..9af93628198 100644 --- a/src/game/editor/mapitems/layer_tiles.h +++ b/src/game/editor/mapitems/layer_tiles.h @@ -2,6 +2,7 @@ #define GAME_EDITOR_MAPITEMS_LAYER_TILES_H #include +#include #include #include "layer.h" @@ -122,6 +123,8 @@ class CLayerTiles : public CLayer void BrushSelecting(CUIRect Rect) override; int BrushGrab(std::shared_ptr pBrush, CUIRect Rect) override; void FillSelection(bool Empty, std::shared_ptr pBrush, CUIRect Rect) override; + void FillGameTiles(EGameTileOp Fill); + bool CanFillGameTiles() const; void BrushDraw(std::shared_ptr pBrush, float wx, float wy) override; void BrushFlipX() override; void BrushFlipY() override; diff --git a/src/game/editor/quick_actions.cpp b/src/game/editor/quick_actions.cpp index 80b07c787de..d1a0639496c 100644 --- a/src/game/editor/quick_actions.cpp +++ b/src/game/editor/quick_actions.cpp @@ -4,12 +4,28 @@ #include "editor_actions.h" +void CEditor::FillGameTiles(EGameTileOp FillTile) const +{ + std::shared_ptr pTileLayer = std::static_pointer_cast(GetSelectedLayerType(0, LAYERTYPE_TILES)); + if(pTileLayer) + pTileLayer->FillGameTiles(FillTile); +} + +bool CEditor::CanFillGameTiles() const +{ + std::shared_ptr pTileLayer = std::static_pointer_cast(GetSelectedLayerType(0, LAYERTYPE_TILES)); + if(pTileLayer) + return pTileLayer->CanFillGameTiles(); + return false; +} + void CEditor::AddGroup() { m_Map.NewGroup(); m_SelectedGroup = m_Map.m_vpGroups.size() - 1; m_EditorHistory.RecordAction(std::make_shared(this, m_SelectedGroup, false)); } + void CEditor::AddTileLayer() { std::shared_ptr pTileLayer = std::make_shared(this, m_Map.m_pGameLayer->m_Width, m_Map.m_pGameLayer->m_Height); diff --git a/src/game/editor/quick_actions.h b/src/game/editor/quick_actions.h index 8264b043245..a13b3008ddc 100644 --- a/src/game/editor/quick_actions.h +++ b/src/game/editor/quick_actions.h @@ -7,6 +7,110 @@ #define ALWAYS_FALSE []() -> bool { return false; } #define DEFAULT_BTN []() -> int { return -1; } +REGISTER_QUICK_ACTION( + GameTilesAir, + "Game tiles: Air", + [&]() { FillGameTiles(EGameTileOp::AIR); }, + [&]() -> bool { return !CanFillGameTiles(); }, + ALWAYS_FALSE, + DEFAULT_BTN, + "") +REGISTER_QUICK_ACTION( + GameTilesHookable, + "Game tiles: Hookable", + [&]() { FillGameTiles(EGameTileOp::HOOKABLE); }, + [&]() -> bool { return !CanFillGameTiles(); }, + ALWAYS_FALSE, + DEFAULT_BTN, + "") +REGISTER_QUICK_ACTION( + GameTilesDeath, + "Game tiles: Death", + [&]() { FillGameTiles(EGameTileOp::DEATH); }, + [&]() -> bool { return !CanFillGameTiles(); }, + ALWAYS_FALSE, + DEFAULT_BTN, + "") +REGISTER_QUICK_ACTION( + GameTilesUnhookable, + "Game tiles: Unhookable", + [&]() { FillGameTiles(EGameTileOp::UNHOOKABLE); }, + [&]() -> bool { return !CanFillGameTiles(); }, + ALWAYS_FALSE, + DEFAULT_BTN, + "") +REGISTER_QUICK_ACTION( + GameTilesHookthrough, + "Game tiles: Hookthrough", + [&]() { FillGameTiles(EGameTileOp::HOOKTHROUGH); }, + [&]() -> bool { return !CanFillGameTiles(); }, + ALWAYS_FALSE, + DEFAULT_BTN, + "") +REGISTER_QUICK_ACTION( + GameTilesFreeze, + "Game tiles: Freeze", + [&]() { FillGameTiles(EGameTileOp::FREEZE); }, + [&]() -> bool { return !CanFillGameTiles(); }, + ALWAYS_FALSE, + DEFAULT_BTN, + "") +REGISTER_QUICK_ACTION( + GameTilesUnfreeze, + "Game tiles: Unfreeze", + [&]() { FillGameTiles(EGameTileOp::UNFREEZE); }, + [&]() -> bool { return !CanFillGameTiles(); }, + ALWAYS_FALSE, + DEFAULT_BTN, + "") +REGISTER_QUICK_ACTION( + GameTilesDeepFreeze, + "Game tiles: Deep Freeze", + [&]() { FillGameTiles(EGameTileOp::DEEP_FREEZE); }, + [&]() -> bool { return !CanFillGameTiles(); }, + ALWAYS_FALSE, + DEFAULT_BTN, + "") +REGISTER_QUICK_ACTION( + GameTilesDeepUnfreeze, + "Game tiles: Deep Unfreeze", + [&]() { FillGameTiles(EGameTileOp::DEEP_UNFREEZE); }, + [&]() -> bool { return !CanFillGameTiles(); }, + ALWAYS_FALSE, + DEFAULT_BTN, + "") +REGISTER_QUICK_ACTION( + GameTilesBlueCheckTele, + "Game tiles: Blue Check Tele", + [&]() { FillGameTiles(EGameTileOp::BLUE_CHECK_TELE); }, + [&]() -> bool { return !CanFillGameTiles(); }, + ALWAYS_FALSE, + DEFAULT_BTN, + "") +REGISTER_QUICK_ACTION( + GameTilesRedCheckTele, + "Game tiles: Red Check Tele", + [&]() { FillGameTiles(EGameTileOp::RED_CHECK_TELE); }, + [&]() -> bool { return !CanFillGameTiles(); }, + ALWAYS_FALSE, + DEFAULT_BTN, + "") +REGISTER_QUICK_ACTION( + GameTilesLiveFreeze, + "Game tiles: Live Freeze", + [&]() { FillGameTiles(EGameTileOp::LIVE_FREEZE); }, + [&]() -> bool { return !CanFillGameTiles(); }, + ALWAYS_FALSE, + DEFAULT_BTN, + "") +REGISTER_QUICK_ACTION( + GameTilesLiveUnfreeze, + "Game tiles: Live Unfreeze", + [&]() { FillGameTiles(EGameTileOp::LIVE_UNFREEZE); }, + [&]() -> bool { return !CanFillGameTiles(); }, + ALWAYS_FALSE, + DEFAULT_BTN, + "") REGISTER_QUICK_ACTION( AddGroup, "Add group", [&]() { AddGroup(); }, ALWAYS_FALSE, ALWAYS_FALSE, DEFAULT_BTN, "Adds a new group") REGISTER_QUICK_ACTION( From 5986ee03b9f024f23a816b56755e264282144d15 Mon Sep 17 00:00:00 2001 From: ChillerDragon Date: Sun, 1 Sep 2024 11:37:23 +0800 Subject: [PATCH 22/30] Consistently apply the NOLINT comment for all sounds in FireWeapon Most but not all sound creations in CCharacter::FireWeapon have this NOLINT comment. Somehow clang does not get tripped on all of those. But sooner or later it might. I currently got a new error in my downstream fork when tweaking FireWeapon a bit. So I applied the NOLINT comment to ALL occurences in FireWeapon not only the ones that clangd finds at the moment. --- src/game/server/entities/character.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/game/server/entities/character.cpp b/src/game/server/entities/character.cpp index 8e60014e814..482e9f13517 100644 --- a/src/game/server/entities/character.cpp +++ b/src/game/server/entities/character.cpp @@ -442,7 +442,7 @@ void CCharacter::FireWeapon() if(m_PainSoundTimer <= 0 && !(m_LatestPrevInput.m_Fire & 1)) { m_PainSoundTimer = 1 * Server()->TickSpeed(); - GameServer()->CreateSound(m_Pos, SOUND_PLAYER_PAIN_LONG, TeamMask()); + GameServer()->CreateSound(m_Pos, SOUND_PLAYER_PAIN_LONG, TeamMask()); // NOLINT(clang-analyzer-unix.Malloc) } return; } @@ -459,7 +459,7 @@ void CCharacter::FireWeapon() { // reset objects Hit m_NumObjectsHit = 0; - GameServer()->CreateSound(m_Pos, SOUND_HAMMER_FIRE, TeamMask()); + GameServer()->CreateSound(m_Pos, SOUND_HAMMER_FIRE, TeamMask()); // NOLINT(clang-analyzer-unix.Malloc) Antibot()->OnHammerFire(m_pPlayer->GetCid()); @@ -567,7 +567,7 @@ void CCharacter::FireWeapon() MouseTarget // MouseTarget ); - GameServer()->CreateSound(m_Pos, SOUND_GRENADE_FIRE, TeamMask()); + GameServer()->CreateSound(m_Pos, SOUND_GRENADE_FIRE, TeamMask()); // NOLINT(clang-analyzer-unix.Malloc) } break; @@ -589,7 +589,7 @@ void CCharacter::FireWeapon() m_Core.m_Ninja.m_CurrentMoveTime = g_pData->m_Weapons.m_Ninja.m_Movetime * Server()->TickSpeed() / 1000; m_Core.m_Ninja.m_OldVelAmount = length(m_Core.m_Vel); - GameServer()->CreateSound(m_Pos, SOUND_NINJA_FIRE, TeamMask()); + GameServer()->CreateSound(m_Pos, SOUND_NINJA_FIRE, TeamMask()); // NOLINT(clang-analyzer-unix.Malloc) } break; } From 82ca4bc3357ee52c206a3cdafaa79721e9e4194a Mon Sep 17 00:00:00 2001 From: ChillerDragon Date: Sun, 1 Sep 2024 12:38:27 +0800 Subject: [PATCH 23/30] Use enum instead of magic number in skin color translation --- src/game/server/teeinfo.cpp | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/game/server/teeinfo.cpp b/src/game/server/teeinfo.cpp index 90432fbeb28..5458a1cc262 100644 --- a/src/game/server/teeinfo.cpp +++ b/src/game/server/teeinfo.cpp @@ -78,16 +78,16 @@ void CTeeInfo::ToSixup() { int ColorBody = ColorHSLA(m_ColorBody).UnclampLighting().Pack(ms_DarkestLGT7); int ColorFeet = ColorHSLA(m_ColorFeet).UnclampLighting().Pack(ms_DarkestLGT7); - m_aUseCustomColors[0] = true; - m_aUseCustomColors[1] = true; - m_aUseCustomColors[2] = true; - m_aUseCustomColors[3] = true; - m_aUseCustomColors[4] = true; - m_aSkinPartColors[0] = ColorBody; - m_aSkinPartColors[1] = 0x22FFFFFF; - m_aSkinPartColors[2] = ColorBody; - m_aSkinPartColors[3] = ColorBody; - m_aSkinPartColors[4] = ColorFeet; + m_aUseCustomColors[protocol7::SKINPART_BODY] = true; + m_aUseCustomColors[protocol7::SKINPART_MARKING] = true; + m_aUseCustomColors[protocol7::SKINPART_DECORATION] = true; + m_aUseCustomColors[protocol7::SKINPART_HANDS] = true; + m_aUseCustomColors[protocol7::SKINPART_FEET] = true; + m_aSkinPartColors[protocol7::SKINPART_BODY] = ColorBody; + m_aSkinPartColors[protocol7::SKINPART_MARKING] = 0x22FFFFFF; + m_aSkinPartColors[protocol7::SKINPART_DECORATION] = ColorBody; + m_aSkinPartColors[protocol7::SKINPART_HANDS] = ColorBody; + m_aSkinPartColors[protocol7::SKINPART_FEET] = ColorFeet; } } @@ -137,6 +137,10 @@ void CTeeInfo::FromSixup() str_copy(m_aSkinName, g_aStdSkins[BestSkin].m_aSkinName, sizeof(m_aSkinName)); m_UseCustomColor = true; - m_ColorBody = ColorHSLA(m_aUseCustomColors[0] ? m_aSkinPartColors[0] : 255).UnclampLighting(ms_DarkestLGT7).Pack(ColorHSLA::DARKEST_LGT); - m_ColorFeet = ColorHSLA(m_aUseCustomColors[4] ? m_aSkinPartColors[4] : 255).UnclampLighting(ms_DarkestLGT7).Pack(ColorHSLA::DARKEST_LGT); + m_ColorBody = ColorHSLA(m_aUseCustomColors[protocol7::SKINPART_BODY] ? m_aSkinPartColors[protocol7::SKINPART_BODY] : 255) + .UnclampLighting(ms_DarkestLGT7) + .Pack(ColorHSLA::DARKEST_LGT); + m_ColorFeet = ColorHSLA(m_aUseCustomColors[protocol7::SKINPART_FEET] ? m_aSkinPartColors[protocol7::SKINPART_FEET] : 255) + .UnclampLighting(ms_DarkestLGT7) + .Pack(ColorHSLA::DARKEST_LGT); } From 1b8e402a657590718a46ca4f09d15b2e0be87ac9 Mon Sep 17 00:00:00 2001 From: ChillerDragon Date: Sun, 1 Sep 2024 16:15:11 +0800 Subject: [PATCH 24/30] Use same descriptions for game tile actions as the button --- src/game/editor/quick_actions.h | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/game/editor/quick_actions.h b/src/game/editor/quick_actions.h index d8012117eea..8c1827330eb 100644 --- a/src/game/editor/quick_actions.h +++ b/src/game/editor/quick_actions.h @@ -14,7 +14,7 @@ REGISTER_QUICK_ACTION( [&]() -> bool { return !CanFillGameTiles(); }, ALWAYS_FALSE, DEFAULT_BTN, - "") + "Constructs game tiles from this layer") REGISTER_QUICK_ACTION( GameTilesHookable, "Game tiles: Hookable", @@ -22,7 +22,7 @@ REGISTER_QUICK_ACTION( [&]() -> bool { return !CanFillGameTiles(); }, ALWAYS_FALSE, DEFAULT_BTN, - "") + "Constructs game tiles from this layer") REGISTER_QUICK_ACTION( GameTilesDeath, "Game tiles: Death", @@ -30,7 +30,7 @@ REGISTER_QUICK_ACTION( [&]() -> bool { return !CanFillGameTiles(); }, ALWAYS_FALSE, DEFAULT_BTN, - "") + "Constructs game tiles from this layer") REGISTER_QUICK_ACTION( GameTilesUnhookable, "Game tiles: Unhookable", @@ -38,7 +38,7 @@ REGISTER_QUICK_ACTION( [&]() -> bool { return !CanFillGameTiles(); }, ALWAYS_FALSE, DEFAULT_BTN, - "") + "Constructs game tiles from this layer") REGISTER_QUICK_ACTION( GameTilesHookthrough, "Game tiles: Hookthrough", @@ -46,7 +46,7 @@ REGISTER_QUICK_ACTION( [&]() -> bool { return !CanFillGameTiles(); }, ALWAYS_FALSE, DEFAULT_BTN, - "") + "Constructs game tiles from this layer") REGISTER_QUICK_ACTION( GameTilesFreeze, "Game tiles: Freeze", @@ -54,7 +54,7 @@ REGISTER_QUICK_ACTION( [&]() -> bool { return !CanFillGameTiles(); }, ALWAYS_FALSE, DEFAULT_BTN, - "") + "Constructs game tiles from this layer") REGISTER_QUICK_ACTION( GameTilesUnfreeze, "Game tiles: Unfreeze", @@ -62,7 +62,7 @@ REGISTER_QUICK_ACTION( [&]() -> bool { return !CanFillGameTiles(); }, ALWAYS_FALSE, DEFAULT_BTN, - "") + "Constructs game tiles from this layer") REGISTER_QUICK_ACTION( GameTilesDeepFreeze, "Game tiles: Deep Freeze", @@ -70,7 +70,7 @@ REGISTER_QUICK_ACTION( [&]() -> bool { return !CanFillGameTiles(); }, ALWAYS_FALSE, DEFAULT_BTN, - "") + "Constructs game tiles from this layer") REGISTER_QUICK_ACTION( GameTilesDeepUnfreeze, "Game tiles: Deep Unfreeze", @@ -78,7 +78,7 @@ REGISTER_QUICK_ACTION( [&]() -> bool { return !CanFillGameTiles(); }, ALWAYS_FALSE, DEFAULT_BTN, - "") + "Constructs game tiles from this layer") REGISTER_QUICK_ACTION( GameTilesBlueCheckTele, "Game tiles: Blue Check Tele", @@ -86,7 +86,7 @@ REGISTER_QUICK_ACTION( [&]() -> bool { return !CanFillGameTiles(); }, ALWAYS_FALSE, DEFAULT_BTN, - "") + "Constructs game tiles from this layer") REGISTER_QUICK_ACTION( GameTilesRedCheckTele, "Game tiles: Red Check Tele", @@ -94,7 +94,7 @@ REGISTER_QUICK_ACTION( [&]() -> bool { return !CanFillGameTiles(); }, ALWAYS_FALSE, DEFAULT_BTN, - "") + "Constructs game tiles from this layer") REGISTER_QUICK_ACTION( GameTilesLiveFreeze, "Game tiles: Live Freeze", @@ -102,7 +102,7 @@ REGISTER_QUICK_ACTION( [&]() -> bool { return !CanFillGameTiles(); }, ALWAYS_FALSE, DEFAULT_BTN, - "") + "Constructs game tiles from this layer") REGISTER_QUICK_ACTION( GameTilesLiveUnfreeze, "Game tiles: Live Unfreeze", @@ -110,7 +110,7 @@ REGISTER_QUICK_ACTION( [&]() -> bool { return !CanFillGameTiles(); }, ALWAYS_FALSE, DEFAULT_BTN, - "") + "Constructs game tiles from this layer") REGISTER_QUICK_ACTION( AddGroup, "Add group", [&]() { AddGroup(); }, ALWAYS_FALSE, ALWAYS_FALSE, DEFAULT_BTN, "Adds a new group") REGISTER_QUICK_ACTION( From 9e88ca584684eeefe4c429f2c5b657dd95e556d9 Mon Sep 17 00:00:00 2001 From: veydzh3r <108631328+Veydzher@users.noreply.github.com> Date: Sun, 1 Sep 2024 09:23:03 +0100 Subject: [PATCH 25/30] Update ukrainian.txt --- data/languages/ukrainian.txt | 86 ++++++++++++++++++------------------ 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/data/languages/ukrainian.txt b/data/languages/ukrainian.txt index eaf5b1b4342..73c7d76364b 100644 --- a/data/languages/ukrainian.txt +++ b/data/languages/ukrainian.txt @@ -4,7 +4,7 @@ #modified by: # 404_not_found 2011-07-30 19:50:58 # EGYT5453 (15.05.2024-04.06.2024) -# veydzh3r (31/08/2024 - present) +# veydzh3r (31/08/2024-01/09/2024) ##### /authors ##### ##### translated strings ##### @@ -17,7 +17,7 @@ [Demo player duration] %d min. -== %d хв. +== %dхв %d new mentions == Нових згадок: %d @@ -40,7 +40,7 @@ [Demo player duration] %d sec. -== %d сек. +== %dс %d/%d KiB (%.1f KiB/s) == %d/%d КіБ (%.1f КіБ/с) @@ -53,16 +53,16 @@ == залишилося %dс %i minute left -== Залишилося: %i хв. +== Залишилося: %iхв %i minutes left -== Залишилося: %i хв. +== Залишилося: %iхв %i second left -== Залишилося: %i сек. +== Залишилося: %iс %i seconds left -== Залишилося: %i сек. +== Залишилося: %iс %s wins! == %s перемагає! @@ -77,17 +77,17 @@ == Нових згадок: 9+ A demo with this name already exists -== Демо з цією назвою вже існує +== Демо з цією назвою уже існує A folder with this name already exists -== Тека з цією назвою вже існує +== Тека з цією назвою уже існує [Graphics error] A render command failed. Try to update your GPU drivers. == Помилка в команді відмальовування. Спробуйте оновити драйвери відеокарти. A Tee -== Тії +== тії Abort == Скасувати @@ -121,7 +121,7 @@ AFR == АФР Aim bind -== Прив'язка +== Прив’язка All == Усі @@ -206,7 +206,7 @@ Assets == Текстури Assets directory -== Тека ресурсів +== Тека текстур AUS == АВС @@ -263,7 +263,7 @@ Call vote == Голосувати Can't find a Tutorial server -== Не вдалося знайти сервер-посібник +== Не вдається знайти навчальний сервер Cancel == Скасувати @@ -347,7 +347,7 @@ Connected == Під’єднано Connecting dummy -== Під’єднати даммі +== Під’єднання даммі Connecting to == Під’єднання до @@ -454,7 +454,7 @@ Deactivate == Деактивувати Deactivate all -== Деактивувати усіх +== Деактивувати всіх Deaths == Смерті @@ -463,7 +463,7 @@ Debug mode enabled. Press Ctrl+Shift+D to disable debug mode. == Увімкнено режим налагодження. Натисніть Ctrl+Shift+D, щоб його вимкнути. default -== за стандартом +== типово Default length == Звичайна тривалість @@ -610,7 +610,7 @@ Error saving settings == Помилка збереження налаштувань EUR -== EUR +== ЄВР Example of usage == Приклад використання @@ -838,7 +838,7 @@ Indicate map finish == Позначати пройдені мапи Info Messages -== Інформаційні повідомлення +== Інфо. повідомлення Ingame controller mode == Режим контролера у грі @@ -877,7 +877,7 @@ Join red == До червоних Join Tutorial Server -== Приєднатися до сервера-посібника +== Приєднатися до навчального сервера Jump == Стрибок @@ -910,7 +910,7 @@ Lht. == Світл. Lines %d - %d (%s) -== Рядки %d — %d (%s) +== Рядки %d—%d (%s) Loading… == Завантаження… @@ -925,7 +925,7 @@ Loading DDNet Client == Завантаження клієнта DDNet Loading demo file from storage -== Завантаження демо-файла зі сховища +== Завантаження демо-файлу зі сховища Loading demo files == Завантаження демо-файлів @@ -971,7 +971,7 @@ map not included == мапу не включено Map sound volume -== Гучність мапи +== Гучність звуків мапи Mark the beginning of a cut (right click to reset) == Позначити початок фрагмента (права кнопка миші, щоб скинути) @@ -986,13 +986,13 @@ Match %d of %d == Збіг %d з %d Max CSVs -== Найбільше CSV-файлів +== Макс. кількість файлів CSV Max demos -== Найбільше демо-файлів +== Макс. кількість демо-файлів Max Screenshots -== Найбільше знімків екрана +== Макс. кількість знімків екрана may cause delay == може спричинити затримку @@ -1031,7 +1031,7 @@ Multi-View == Мульти-камера Mute when not active -== Приглушувати, якщо вікно неактивне +== Приглушувати звук поза грою NA == ПНА @@ -1052,7 +1052,7 @@ Netversion == Версія New name: -== Нова назва +== Нова назва: New random timeout code == Новий випадковий код тайм-ауту @@ -1134,7 +1134,7 @@ Only save improvements == Зберігати лише покращення Opacity -== Непрозорість +== Непрозор. Opacity of freeze bars inside freeze == Непрозорість смуги заморозки в заморозці @@ -1159,7 +1159,7 @@ Open the settings file [Graphics error] Out of VRAM. Try removing custom assets (skins, entities, etc.), especially those with high resolution. -== Недостатньо відеопам’яті. Спробуйте видалити власні текстури (скіни, сутності і т.п.), особливо ті, що мають високу роздільність. +== Недостатньо відеопам’яті. Спробуйте видалити власні текстури (скіни, сутності і т.д.), особливо ті, що мають високу роздільність. Overlay entities == Накладати сутності @@ -1171,7 +1171,7 @@ Particles == Частинки Pause -== Павза +== Пауза Pause the current demo == Призупинити @@ -1262,7 +1262,7 @@ Reason: == Причина: Reconnect in %d sec -== Повторне під’єднання за %d сек. +== Повторне під’єднання за %dс Record demo == Запис демо @@ -1274,7 +1274,7 @@ Red team wins! == Червоні перемогли! Refresh Rate -== Частота оновлення +== Частота кадрів Regular background color == Колір звичайного тла @@ -1365,7 +1365,7 @@ Same clan color in scoreboard == Колір співклановців у таблиці Sat. -== Насиченість +== Насич. Save == Зберегти @@ -1374,7 +1374,7 @@ Save ghost == Зберігати привида Save power by lowering refresh rate (higher input latency) -== Економія енергії шляхом зниження частоти оновлення (вища затримка введення) +== Економити енергію шляхом зниження частоти кадрів (вища затримка введення) Save the best demo of each race == Зберігати найкраще демо кожного забігу @@ -1452,7 +1452,7 @@ Show clan above name plates == Показувати клан над ніками Show client IDs (scoreboard, chat, spectator) -== Показувати ID клієнта (табло, чат, спостерігачі) +== Показувати ID клієнта (таблиця, чат, спостерігачі) Show DDNet map finishes in server browser == Показувати пройдені мапи DDNet у браузері серверів @@ -1464,7 +1464,7 @@ Show dummy actions == Показувати дії з даммі Show entities -== Показувати сутності +== Показ сутностей Show finish messages == Показувати повідомлення про фініші @@ -1666,7 +1666,7 @@ Switch weapon on pickup == Змінювати зброю при підхопленні Switch weapon when out of ammo -== Змінювати зброю коли закінчуються набої +== Змінювати зброю при закінченні набоїв System message == Повідомлення системи @@ -1732,7 +1732,7 @@ Toggle ghost == Привид Toggle keyboard shortcuts -== Перемкнути скорочення +== Перемкнути сполучення Toggle to edit your dummy settings == Перемкніть, щоб змінити налаштування даммі @@ -1747,7 +1747,7 @@ Try again == Спробувати ще раз Trying to determine UDP connectivity… -== Намагаємося визначити UDP-з'єднання… +== Спроба визначити UDP-з’єднання… Tutorial == Посібник @@ -1768,10 +1768,10 @@ UI Color == Колір інтерфейсу UI controller sens. -== Чутливість в інтерфейсі +== Чутл. в інтерфейсі UI mouse sens. -== Чутливість в інтерфейсі +== Чутл. в інтерфейсі Unable to delete skin == Не вдалося видалити скін @@ -1841,7 +1841,7 @@ Video name: == Назва відео: Video was saved to '%s' -== Відео було збережено до '%s' +== Відео збережено до '%s' Videos directory == Тека відео @@ -1901,7 +1901,7 @@ Your movements are not taken into account when calculating the line colors == Ваші рухи не враховуються при розранку кольору лінії You must restart the game for all settings to take effect. -== Щоб налаштування набрали чинності, перезапустіть гру. +== Щоб налаштування набули чинності, перезапустіть гру. Your nickname '%s' is already used (%d points). Do you still want to use it? == Ваш псевдонім «%s» вже зайнято (%d балів). Усе ще хочете використовувати його? From 8b304cab238ec3ffdb30cc9d73d9f47cc95c1212 Mon Sep 17 00:00:00 2001 From: ChillerDragon Date: Sun, 1 Sep 2024 16:23:04 +0800 Subject: [PATCH 26/30] Add quick action "Toggle Grid" --- src/game/editor/editor.cpp | 4 ++-- src/game/editor/quick_actions.h | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/game/editor/editor.cpp b/src/game/editor/editor.cpp index 978716bbf93..3ba8add6c76 100644 --- a/src/game/editor/editor.cpp +++ b/src/game/editor/editor.cpp @@ -1102,10 +1102,10 @@ void CEditor::DoToolbarLayers(CUIRect ToolBar) // grid button TB_Top.VSplitLeft(25.0f, &Button, &TB_Top); static int s_GridButton = 0; - if(DoButton_FontIcon(&s_GridButton, FONT_ICON_BORDER_ALL, MapView()->MapGrid()->IsEnabled(), &Button, 0, "[ctrl+g] Toggle Grid", IGraphics::CORNER_L) || + if(DoButton_FontIcon(&s_GridButton, FONT_ICON_BORDER_ALL, m_QuickActionToggleGrid.Active(), &Button, 0, m_QuickActionToggleGrid.Description(), IGraphics::CORNER_L) || (m_Dialog == DIALOG_NONE && CLineInput::GetActiveInput() == nullptr && Input()->KeyPress(KEY_G) && ModPressed && !ShiftPressed)) { - MapView()->MapGrid()->Toggle(); + m_QuickActionToggleGrid.Call(); } // grid settings button diff --git a/src/game/editor/quick_actions.h b/src/game/editor/quick_actions.h index d8012117eea..e58ed6a2d64 100644 --- a/src/game/editor/quick_actions.h +++ b/src/game/editor/quick_actions.h @@ -7,6 +7,14 @@ #define ALWAYS_FALSE []() -> bool { return false; } #define DEFAULT_BTN []() -> int { return -1; } +REGISTER_QUICK_ACTION( + ToggleGrid, + "Toggle Grid", + [&]() { MapView()->MapGrid()->Toggle(); }, + ALWAYS_FALSE, + [&]() -> bool { return MapView()->MapGrid()->IsEnabled(); }, + DEFAULT_BTN, + "[ctrl+g] Toggle Grid") REGISTER_QUICK_ACTION( GameTilesAir, "Game tiles: Air", From 403c4a40da84b210a8c65fe7f0e83d91cba8c8c1 Mon Sep 17 00:00:00 2001 From: veydzh3r <108631328+Veydzher@users.noreply.github.com> Date: Sun, 1 Sep 2024 10:20:44 +0100 Subject: [PATCH 27/30] Update ukrainian.txt --- data/languages/ukrainian.txt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/data/languages/ukrainian.txt b/data/languages/ukrainian.txt index 73c7d76364b..c5c82d47e06 100644 --- a/data/languages/ukrainian.txt +++ b/data/languages/ukrainian.txt @@ -4,7 +4,7 @@ #modified by: # 404_not_found 2011-07-30 19:50:58 # EGYT5453 (15.05.2024-04.06.2024) -# veydzh3r (31/08/2024-01/09/2024) +# veydzh3r (31.08.2024-01.09.2024) ##### /authors ##### ##### translated strings ##### @@ -33,10 +33,10 @@ == ще %d… %d player -== Гравців: %d +== Гравці: %d %d players -== Гравців: %d +== Гравці: %d [Demo player duration] %d sec. @@ -194,7 +194,7 @@ Are you sure that you want to remove the player '%s' from your friends list? == Ви дійсно хочете прибрати гравця '%s' зі списку друзів? Are you sure that you want to reset the controls to their defaults? -== Ви дійсно хочете скинути налаштування керувань до стандартних значень? +== Ви дійсно хочете скинути налаштування керувань до початкових значень? Are you sure that you want to restart? == Ви дійсно хочете перезапустити? @@ -302,7 +302,7 @@ CHN == КИТ Choose default eyes when joining a server -== Стандартні очі під час приєднання до сервера +== Типові очі під час приєднання до сервера Clan == Клан @@ -381,7 +381,7 @@ Could not connect dummy [Graphics error] Could not initialize the given graphics backend, reverting to the default backend now. -== Не вдалося ініціалізувати заданий графічний рушій, повертаємося до стандартного рушія. +== Не вдалося ініціалізувати заданий графічний рушій, повернення до тпового рушія. [Graphics error] Could not initialize the given graphics backend, this is probably because you didn't install the driver of the integrated graphics card. @@ -1016,7 +1016,7 @@ Move left == Вліво Move player to spectators -== Зробити гравця спостерігачем +== Зробити гравця глядачем Move right == Вправо @@ -1452,7 +1452,7 @@ Show clan above name plates == Показувати клан над ніками Show client IDs (scoreboard, chat, spectator) -== Показувати ID клієнта (таблиця, чат, спостерігачі) +== Показувати ID клієнта (таблиці, чату, глядачів) Show DDNet map finishes in server browser == Показувати пройдені мапи DDNet у браузері серверів From 624ac85e8c209464a6193e039c6e24e5530ea241 Mon Sep 17 00:00:00 2001 From: veydzh3r <108631328+Veydzher@users.noreply.github.com> Date: Sun, 1 Sep 2024 10:29:39 +0100 Subject: [PATCH 28/30] Update ukrainian.txt --- data/languages/ukrainian.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/languages/ukrainian.txt b/data/languages/ukrainian.txt index c5c82d47e06..c31d213da63 100644 --- a/data/languages/ukrainian.txt +++ b/data/languages/ukrainian.txt @@ -1452,7 +1452,7 @@ Show clan above name plates == Показувати клан над ніками Show client IDs (scoreboard, chat, spectator) -== Показувати ID клієнта (таблиці, чату, глядачів) +== Показувати ID клієнта (таблиця, чат, глядачі) Show DDNet map finishes in server browser == Показувати пройдені мапи DDNet у браузері серверів From 2a26c1c5d68d1ee43101af77a98b75cc56bfe009 Mon Sep 17 00:00:00 2001 From: ChillerDragon Date: Sun, 1 Sep 2024 19:17:03 +0800 Subject: [PATCH 29/30] Put dead players at the bottom of the scoreboard Closed #8868 --- src/game/client/components/scoreboard.cpp | 369 +++++++++++----------- 1 file changed, 188 insertions(+), 181 deletions(-) diff --git a/src/game/client/components/scoreboard.cpp b/src/game/client/components/scoreboard.cpp index d37aca6529c..2170c1815c6 100644 --- a/src/game/client/components/scoreboard.cpp +++ b/src/game/client/components/scoreboard.cpp @@ -349,240 +349,247 @@ void CScoreboard::RenderScoreboard(CUIRect Scoreboard, int Team, int CountStart, char aBuf[64]; int MaxTeamSize = m_pClient->Config()->m_SvMaxTeamSize; - for(int i = 0; i < MAX_CLIENTS; i++) + for(int RenderDead = 0; RenderDead < 2; RenderDead++) { - // make sure that we render the correct team - const CNetObj_PlayerInfo *pInfo = GameClient()->m_Snap.m_apInfoByDDTeamScore[i]; - if(!pInfo || pInfo->m_Team != Team) - continue; - - if(CountRendered++ < CountStart) - continue; - - int DDTeam = GameClient()->m_Teams.Team(pInfo->m_ClientId); - int NextDDTeam = 0; - bool RenderDead = Client()->m_TranslationContext.m_aClients[pInfo->m_ClientId].m_PlayerFlags7 & protocol7::PLAYERFLAG_DEAD; + for(int i = 0; i < MAX_CLIENTS; i++) + { + // make sure that we render the correct team + const CNetObj_PlayerInfo *pInfo = GameClient()->m_Snap.m_apInfoByDDTeamScore[i]; + if(!pInfo || pInfo->m_Team != Team) + continue; - ColorRGBA TextColor = TextRender()->DefaultTextColor(); - TextColor.a = RenderDead ? 0.5f : 1.0f; - TextRender()->TextColor(TextColor); + if(CountRendered++ < CountStart) + continue; - for(int j = i + 1; j < MAX_CLIENTS; j++) - { - const CNetObj_PlayerInfo *pInfoNext = GameClient()->m_Snap.m_apInfoByDDTeamScore[j]; - if(!pInfoNext || pInfoNext->m_Team != Team) + int DDTeam = GameClient()->m_Teams.Team(pInfo->m_ClientId); + int NextDDTeam = 0; + bool IsDead = Client()->m_TranslationContext.m_aClients[pInfo->m_ClientId].m_PlayerFlags7 & protocol7::PLAYERFLAG_DEAD; + if(!RenderDead && IsDead) + continue; + if(RenderDead && !IsDead) continue; - NextDDTeam = GameClient()->m_Teams.Team(pInfoNext->m_ClientId); - break; - } + ColorRGBA TextColor = TextRender()->DefaultTextColor(); + TextColor.a = RenderDead ? 0.5f : 1.0f; + TextRender()->TextColor(TextColor); - if(PrevDDTeam == -1) - { - for(int j = i - 1; j >= 0; j--) + for(int j = i + 1; j < MAX_CLIENTS; j++) { - const CNetObj_PlayerInfo *pInfoPrev = GameClient()->m_Snap.m_apInfoByDDTeamScore[j]; - if(!pInfoPrev || pInfoPrev->m_Team != Team) + const CNetObj_PlayerInfo *pInfoNext = GameClient()->m_Snap.m_apInfoByDDTeamScore[j]; + if(!pInfoNext || pInfoNext->m_Team != Team) continue; - PrevDDTeam = GameClient()->m_Teams.Team(pInfoPrev->m_ClientId); + NextDDTeam = GameClient()->m_Teams.Team(pInfoNext->m_ClientId); break; } - } - - CUIRect RowAndSpacing, Row; - Scoreboard.HSplitTop(LineHeight + Spacing, &RowAndSpacing, &Scoreboard); - RowAndSpacing.HSplitTop(LineHeight, &Row, nullptr); - // team background - if(DDTeam != TEAM_FLOCK) - { - const ColorRGBA Color = GameClient()->GetDDTeamColor(DDTeam).WithAlpha(0.5f); - int TeamRectCorners = 0; - if(PrevDDTeam != DDTeam) + if(PrevDDTeam == -1) { - TeamRectCorners |= IGraphics::CORNER_T; - State.m_TeamStartX = Row.x; - State.m_TeamStartY = Row.y; + for(int j = i - 1; j >= 0; j--) + { + const CNetObj_PlayerInfo *pInfoPrev = GameClient()->m_Snap.m_apInfoByDDTeamScore[j]; + if(!pInfoPrev || pInfoPrev->m_Team != Team) + continue; + + PrevDDTeam = GameClient()->m_Teams.Team(pInfoPrev->m_ClientId); + break; + } } - if(NextDDTeam != DDTeam) - TeamRectCorners |= IGraphics::CORNER_B; - RowAndSpacing.Draw(Color, TeamRectCorners, RoundRadius); - CurrentDDTeamSize++; + CUIRect RowAndSpacing, Row; + Scoreboard.HSplitTop(LineHeight + Spacing, &RowAndSpacing, &Scoreboard); + RowAndSpacing.HSplitTop(LineHeight, &Row, nullptr); - if(NextDDTeam != DDTeam) + // team background + if(DDTeam != TEAM_FLOCK) { - const float TeamFontSize = FontSize / 1.5f; - - if(NumPlayers > 8) + const ColorRGBA Color = GameClient()->GetDDTeamColor(DDTeam).WithAlpha(0.5f); + int TeamRectCorners = 0; + if(PrevDDTeam != DDTeam) { - if(DDTeam == TEAM_SUPER) - str_copy(aBuf, Localize("Super")); - else if(CurrentDDTeamSize <= 1) - str_format(aBuf, sizeof(aBuf), "%d", DDTeam); - else - str_format(aBuf, sizeof(aBuf), Localize("%d\n(%d/%d)", "Team and size"), DDTeam, CurrentDDTeamSize, MaxTeamSize); - TextRender()->Text(State.m_TeamStartX, maximum(State.m_TeamStartY + Row.h / 2.0f - TeamFontSize, State.m_TeamStartY + 3.0f /* padding top */), TeamFontSize, aBuf); + TeamRectCorners |= IGraphics::CORNER_T; + State.m_TeamStartX = Row.x; + State.m_TeamStartY = Row.y; } - else + if(NextDDTeam != DDTeam) + TeamRectCorners |= IGraphics::CORNER_B; + RowAndSpacing.Draw(Color, TeamRectCorners, RoundRadius); + + CurrentDDTeamSize++; + + if(NextDDTeam != DDTeam) { - if(DDTeam == TEAM_SUPER) - str_copy(aBuf, Localize("Super")); - else if(CurrentDDTeamSize > 1) - str_format(aBuf, sizeof(aBuf), Localize("Team %d (%d/%d)"), DDTeam, CurrentDDTeamSize, MaxTeamSize); + const float TeamFontSize = FontSize / 1.5f; + + if(NumPlayers > 8) + { + if(DDTeam == TEAM_SUPER) + str_copy(aBuf, Localize("Super")); + else if(CurrentDDTeamSize <= 1) + str_format(aBuf, sizeof(aBuf), "%d", DDTeam); + else + str_format(aBuf, sizeof(aBuf), Localize("%d\n(%d/%d)", "Team and size"), DDTeam, CurrentDDTeamSize, MaxTeamSize); + TextRender()->Text(State.m_TeamStartX, maximum(State.m_TeamStartY + Row.h / 2.0f - TeamFontSize, State.m_TeamStartY + 3.0f /* padding top */), TeamFontSize, aBuf); + } else - str_format(aBuf, sizeof(aBuf), Localize("Team %d"), DDTeam); - TextRender()->Text(Row.x + Row.w / 2.0f - TextRender()->TextWidth(TeamFontSize, aBuf) / 2.0f + 10.0f, Row.y + Row.h, TeamFontSize, aBuf); + { + if(DDTeam == TEAM_SUPER) + str_copy(aBuf, Localize("Super")); + else if(CurrentDDTeamSize > 1) + str_format(aBuf, sizeof(aBuf), Localize("Team %d (%d/%d)"), DDTeam, CurrentDDTeamSize, MaxTeamSize); + else + str_format(aBuf, sizeof(aBuf), Localize("Team %d"), DDTeam); + TextRender()->Text(Row.x + Row.w / 2.0f - TextRender()->TextWidth(TeamFontSize, aBuf) / 2.0f + 10.0f, Row.y + Row.h, TeamFontSize, aBuf); + } + + CurrentDDTeamSize = 0; } - - CurrentDDTeamSize = 0; } - } - PrevDDTeam = DDTeam; - - // background so it's easy to find the local player or the followed one in spectator mode - if((!GameClient()->m_Snap.m_SpecInfo.m_Active && pInfo->m_Local) || - (GameClient()->m_Snap.m_SpecInfo.m_SpectatorId == SPEC_FREEVIEW && pInfo->m_Local) || - (GameClient()->m_Snap.m_SpecInfo.m_Active && pInfo->m_ClientId == GameClient()->m_Snap.m_SpecInfo.m_SpectatorId)) - { - Row.Draw(ColorRGBA(1.0f, 1.0f, 1.0f, 0.25f), IGraphics::CORNER_ALL, RoundRadius); - } + PrevDDTeam = DDTeam; - // score - if(Race7) - { - if(pInfo->m_Score == -1) + // background so it's easy to find the local player or the followed one in spectator mode + if((!GameClient()->m_Snap.m_SpecInfo.m_Active && pInfo->m_Local) || + (GameClient()->m_Snap.m_SpecInfo.m_SpectatorId == SPEC_FREEVIEW && pInfo->m_Local) || + (GameClient()->m_Snap.m_SpecInfo.m_Active && pInfo->m_ClientId == GameClient()->m_Snap.m_SpecInfo.m_SpectatorId)) { - aBuf[0] = '\0'; + Row.Draw(ColorRGBA(1.0f, 1.0f, 1.0f, 0.25f), IGraphics::CORNER_ALL, RoundRadius); } - else + + // score + if(Race7) { - // 0.7 uses milliseconds and ddnets str_time wants centiseconds - // 0.7 servers can also send the amount of precision the client should use - // we ignore that and always show 3 digit precision - str_time((int64_t)absolute(pInfo->m_Score / 10), TIME_MINS_CENTISECS, aBuf, sizeof(aBuf)); + if(pInfo->m_Score == -1) + { + aBuf[0] = '\0'; + } + else + { + // 0.7 uses milliseconds and ddnets str_time wants centiseconds + // 0.7 servers can also send the amount of precision the client should use + // we ignore that and always show 3 digit precision + str_time((int64_t)absolute(pInfo->m_Score / 10), TIME_MINS_CENTISECS, aBuf, sizeof(aBuf)); + } } - } - else if(TimeScore) - { - if(pInfo->m_Score == -9999) + else if(TimeScore) { - aBuf[0] = '\0'; + if(pInfo->m_Score == -9999) + { + aBuf[0] = '\0'; + } + else + { + str_time((int64_t)absolute(pInfo->m_Score) * 100, TIME_HOURS, aBuf, sizeof(aBuf)); + } } else { - str_time((int64_t)absolute(pInfo->m_Score) * 100, TIME_HOURS, aBuf, sizeof(aBuf)); + str_format(aBuf, sizeof(aBuf), "%d", clamp(pInfo->m_Score, -999, 99999)); } - } - else - { - str_format(aBuf, sizeof(aBuf), "%d", clamp(pInfo->m_Score, -999, 99999)); - } - TextRender()->Text(ScoreOffset + ScoreLength - TextRender()->TextWidth(FontSize, aBuf), Row.y + (Row.h - FontSize) / 2.0f, FontSize, aBuf); + TextRender()->Text(ScoreOffset + ScoreLength - TextRender()->TextWidth(FontSize, aBuf), Row.y + (Row.h - FontSize) / 2.0f, FontSize, aBuf); - // CTF flag - if(pGameInfoObj && (pGameInfoObj->m_GameFlags & GAMEFLAG_FLAGS) && - pGameDataObj && (pGameDataObj->m_FlagCarrierRed == pInfo->m_ClientId || pGameDataObj->m_FlagCarrierBlue == pInfo->m_ClientId)) - { - Graphics()->BlendNormal(); - Graphics()->TextureSet(pGameDataObj->m_FlagCarrierBlue == pInfo->m_ClientId ? GameClient()->m_GameSkin.m_SpriteFlagBlue : GameClient()->m_GameSkin.m_SpriteFlagRed); - Graphics()->QuadsBegin(); - Graphics()->QuadsSetSubset(1.0f, 0.0f, 0.0f, 1.0f); - IGraphics::CQuadItem QuadItem(TeeOffset, Row.y - 5.0f - Spacing / 2.0f, Row.h / 2.0f, Row.h); - Graphics()->QuadsDrawTL(&QuadItem, 1); - Graphics()->QuadsEnd(); - } + // CTF flag + if(pGameInfoObj && (pGameInfoObj->m_GameFlags & GAMEFLAG_FLAGS) && + pGameDataObj && (pGameDataObj->m_FlagCarrierRed == pInfo->m_ClientId || pGameDataObj->m_FlagCarrierBlue == pInfo->m_ClientId)) + { + Graphics()->BlendNormal(); + Graphics()->TextureSet(pGameDataObj->m_FlagCarrierBlue == pInfo->m_ClientId ? GameClient()->m_GameSkin.m_SpriteFlagBlue : GameClient()->m_GameSkin.m_SpriteFlagRed); + Graphics()->QuadsBegin(); + Graphics()->QuadsSetSubset(1.0f, 0.0f, 0.0f, 1.0f); + IGraphics::CQuadItem QuadItem(TeeOffset, Row.y - 5.0f - Spacing / 2.0f, Row.h / 2.0f, Row.h); + Graphics()->QuadsDrawTL(&QuadItem, 1); + Graphics()->QuadsEnd(); + } - const CGameClient::CClientData &ClientData = GameClient()->m_aClients[pInfo->m_ClientId]; + const CGameClient::CClientData &ClientData = GameClient()->m_aClients[pInfo->m_ClientId]; - // skin - if(RenderDead) - { - Graphics()->BlendNormal(); - Graphics()->TextureSet(client_data7::g_pData->m_aImages[client_data7::IMAGE_DEADTEE].m_Id); - Graphics()->QuadsBegin(); - if(m_pClient->m_Snap.m_pGameInfoObj->m_GameFlags & GAMEFLAG_TEAMS) + // skin + if(RenderDead) { - ColorRGBA Color = m_pClient->m_Skins7.GetTeamColor(true, 0, m_pClient->m_aClients[pInfo->m_ClientId].m_Team, protocol7::SKINPART_BODY); - Graphics()->SetColor(Color.r, Color.g, Color.b, Color.a); + Graphics()->BlendNormal(); + Graphics()->TextureSet(client_data7::g_pData->m_aImages[client_data7::IMAGE_DEADTEE].m_Id); + Graphics()->QuadsBegin(); + if(m_pClient->m_Snap.m_pGameInfoObj->m_GameFlags & GAMEFLAG_TEAMS) + { + ColorRGBA Color = m_pClient->m_Skins7.GetTeamColor(true, 0, m_pClient->m_aClients[pInfo->m_ClientId].m_Team, protocol7::SKINPART_BODY); + Graphics()->SetColor(Color.r, Color.g, Color.b, Color.a); + } + CTeeRenderInfo TeeInfo = m_pClient->m_aClients[pInfo->m_ClientId].m_RenderInfo; + TeeInfo.m_Size *= TeeSizeMod; + IGraphics::CQuadItem QuadItem(TeeOffset, Row.y, TeeInfo.m_Size, TeeInfo.m_Size); + Graphics()->QuadsDrawTL(&QuadItem, 1); + Graphics()->QuadsEnd(); } - CTeeRenderInfo TeeInfo = m_pClient->m_aClients[pInfo->m_ClientId].m_RenderInfo; - TeeInfo.m_Size *= TeeSizeMod; - IGraphics::CQuadItem QuadItem(TeeOffset, Row.y, TeeInfo.m_Size, TeeInfo.m_Size); - Graphics()->QuadsDrawTL(&QuadItem, 1); - Graphics()->QuadsEnd(); - } - else - { - CTeeRenderInfo TeeInfo = ClientData.m_RenderInfo; - TeeInfo.m_Size *= TeeSizeMod; - vec2 OffsetToMid; - CRenderTools::GetRenderTeeOffsetToRenderedTee(CAnimState::GetIdle(), &TeeInfo, OffsetToMid); - const vec2 TeeRenderPos = vec2(TeeOffset + TeeLength / 2, Row.y + Row.h / 2.0f + OffsetToMid.y); - RenderTools()->RenderTee(CAnimState::GetIdle(), &TeeInfo, EMOTE_NORMAL, vec2(1.0f, 0.0f), TeeRenderPos); - } - - // name - { - CTextCursor Cursor; - TextRender()->SetCursor(&Cursor, NameOffset, Row.y + (Row.h - FontSize) / 2.0f, FontSize, TEXTFLAG_RENDER | TEXTFLAG_ELLIPSIS_AT_END); - Cursor.m_LineWidth = NameLength; - if(ClientData.m_AuthLevel) + else { - TextRender()->TextColor(color_cast(ColorHSLA(g_Config.m_ClAuthedPlayerColor))); + CTeeRenderInfo TeeInfo = ClientData.m_RenderInfo; + TeeInfo.m_Size *= TeeSizeMod; + vec2 OffsetToMid; + CRenderTools::GetRenderTeeOffsetToRenderedTee(CAnimState::GetIdle(), &TeeInfo, OffsetToMid); + const vec2 TeeRenderPos = vec2(TeeOffset + TeeLength / 2, Row.y + Row.h / 2.0f + OffsetToMid.y); + RenderTools()->RenderTee(CAnimState::GetIdle(), &TeeInfo, EMOTE_NORMAL, vec2(1.0f, 0.0f), TeeRenderPos); } - if(g_Config.m_ClShowIds) + + // name { - char aClientId[16]; - GameClient()->FormatClientId(pInfo->m_ClientId, aClientId, EClientIdFormat::INDENT_AUTO); - TextRender()->TextEx(&Cursor, aClientId); + CTextCursor Cursor; + TextRender()->SetCursor(&Cursor, NameOffset, Row.y + (Row.h - FontSize) / 2.0f, FontSize, TEXTFLAG_RENDER | TEXTFLAG_ELLIPSIS_AT_END); + Cursor.m_LineWidth = NameLength; + if(ClientData.m_AuthLevel) + { + TextRender()->TextColor(color_cast(ColorHSLA(g_Config.m_ClAuthedPlayerColor))); + } + if(g_Config.m_ClShowIds) + { + char aClientId[16]; + GameClient()->FormatClientId(pInfo->m_ClientId, aClientId, EClientIdFormat::INDENT_AUTO); + TextRender()->TextEx(&Cursor, aClientId); + } + TextRender()->TextEx(&Cursor, ClientData.m_aName); + + // ready / watching + if(Client()->IsSixup() && Client()->m_TranslationContext.m_aClients[pInfo->m_ClientId].m_PlayerFlags7 & protocol7::PLAYERFLAG_READY) + { + TextRender()->TextColor(0.1f, 1.0f, 0.1f, TextColor.a); + TextRender()->TextEx(&Cursor, "✓"); + } } - TextRender()->TextEx(&Cursor, ClientData.m_aName); - // ready / watching - if(Client()->IsSixup() && Client()->m_TranslationContext.m_aClients[pInfo->m_ClientId].m_PlayerFlags7 & protocol7::PLAYERFLAG_READY) + // clan { - TextRender()->TextColor(0.1f, 1.0f, 0.1f, TextColor.a); - TextRender()->TextEx(&Cursor, "✓"); + if(str_comp(ClientData.m_aClan, GameClient()->m_aClients[GameClient()->m_aLocalIds[g_Config.m_ClDummy]].m_aClan) == 0) + { + TextRender()->TextColor(color_cast(ColorHSLA(g_Config.m_ClSameClanColor))); + } + else + { + TextRender()->TextColor(TextColor); + } + CTextCursor Cursor; + TextRender()->SetCursor(&Cursor, ClanOffset + (ClanLength - minimum(TextRender()->TextWidth(FontSize, ClientData.m_aClan), ClanLength)) / 2.0f, Row.y + (Row.h - FontSize) / 2.0f, FontSize, TEXTFLAG_RENDER | TEXTFLAG_ELLIPSIS_AT_END); + Cursor.m_LineWidth = ClanLength; + TextRender()->TextEx(&Cursor, ClientData.m_aClan); } - } - // clan - { - if(str_comp(ClientData.m_aClan, GameClient()->m_aClients[GameClient()->m_aLocalIds[g_Config.m_ClDummy]].m_aClan) == 0) + // country flag + GameClient()->m_CountryFlags.Render(ClientData.m_Country, ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f), + CountryOffset, Row.y + (Spacing + TeeSizeMod * 5.0f) / 2.0f, CountryLength, Row.h - Spacing - TeeSizeMod * 5.0f); + + // ping + if(g_Config.m_ClEnablePingColor) { - TextRender()->TextColor(color_cast(ColorHSLA(g_Config.m_ClSameClanColor))); + TextRender()->TextColor(color_cast(ColorHSLA((300.0f - clamp(pInfo->m_Latency, 0, 300)) / 1000.0f, 1.0f, 0.5f))); } else { - TextRender()->TextColor(TextColor); + TextRender()->TextColor(TextRender()->DefaultTextColor()); } - CTextCursor Cursor; - TextRender()->SetCursor(&Cursor, ClanOffset + (ClanLength - minimum(TextRender()->TextWidth(FontSize, ClientData.m_aClan), ClanLength)) / 2.0f, Row.y + (Row.h - FontSize) / 2.0f, FontSize, TEXTFLAG_RENDER | TEXTFLAG_ELLIPSIS_AT_END); - Cursor.m_LineWidth = ClanLength; - TextRender()->TextEx(&Cursor, ClientData.m_aClan); - } - - // country flag - GameClient()->m_CountryFlags.Render(ClientData.m_Country, ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f), - CountryOffset, Row.y + (Spacing + TeeSizeMod * 5.0f) / 2.0f, CountryLength, Row.h - Spacing - TeeSizeMod * 5.0f); - - // ping - if(g_Config.m_ClEnablePingColor) - { - TextRender()->TextColor(color_cast(ColorHSLA((300.0f - clamp(pInfo->m_Latency, 0, 300)) / 1000.0f, 1.0f, 0.5f))); - } - else - { + str_format(aBuf, sizeof(aBuf), "%d", clamp(pInfo->m_Latency, 0, 999)); + TextRender()->Text(PingOffset + PingLength - TextRender()->TextWidth(FontSize, aBuf), Row.y + (Row.h - FontSize) / 2.0f, FontSize, aBuf); TextRender()->TextColor(TextRender()->DefaultTextColor()); - } - str_format(aBuf, sizeof(aBuf), "%d", clamp(pInfo->m_Latency, 0, 999)); - TextRender()->Text(PingOffset + PingLength - TextRender()->TextWidth(FontSize, aBuf), Row.y + (Row.h - FontSize) / 2.0f, FontSize, aBuf); - TextRender()->TextColor(TextRender()->DefaultTextColor()); - if(CountRendered == CountEnd) - break; + if(CountRendered == CountEnd) + break; + } } } From a0171907539505ccdb3a3d6bceee82cdd369ae00 Mon Sep 17 00:00:00 2001 From: BlaiZephyr Date: Sun, 1 Sep 2024 20:01:21 +0200 Subject: [PATCH 30/30] fix inconsistent quickaction labels --- src/game/editor/quick_actions.h | 58 ++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 23 deletions(-) diff --git a/src/game/editor/quick_actions.h b/src/game/editor/quick_actions.h index adc8a989127..cfba08e4be6 100644 --- a/src/game/editor/quick_actions.h +++ b/src/game/editor/quick_actions.h @@ -14,7 +14,7 @@ REGISTER_QUICK_ACTION( ALWAYS_FALSE, [&]() -> bool { return MapView()->MapGrid()->IsEnabled(); }, DEFAULT_BTN, - "[ctrl+g] Toggle Grid") + "[Ctrl+G] Toggle Grid.") REGISTER_QUICK_ACTION( GameTilesAir, "Game tiles: Air", @@ -22,7 +22,7 @@ REGISTER_QUICK_ACTION( [&]() -> bool { return !CanFillGameTiles(); }, ALWAYS_FALSE, DEFAULT_BTN, - "Constructs game tiles from this layer") + "Constructs game tiles from this layer.") REGISTER_QUICK_ACTION( GameTilesHookable, "Game tiles: Hookable", @@ -30,7 +30,7 @@ REGISTER_QUICK_ACTION( [&]() -> bool { return !CanFillGameTiles(); }, ALWAYS_FALSE, DEFAULT_BTN, - "Constructs game tiles from this layer") + "Constructs game tiles from this layer.") REGISTER_QUICK_ACTION( GameTilesDeath, "Game tiles: Death", @@ -38,7 +38,7 @@ REGISTER_QUICK_ACTION( [&]() -> bool { return !CanFillGameTiles(); }, ALWAYS_FALSE, DEFAULT_BTN, - "Constructs game tiles from this layer") + "Constructs game tiles from this layer.") REGISTER_QUICK_ACTION( GameTilesUnhookable, "Game tiles: Unhookable", @@ -46,7 +46,7 @@ REGISTER_QUICK_ACTION( [&]() -> bool { return !CanFillGameTiles(); }, ALWAYS_FALSE, DEFAULT_BTN, - "Constructs game tiles from this layer") + "Constructs game tiles from this layer.") REGISTER_QUICK_ACTION( GameTilesHookthrough, "Game tiles: Hookthrough", @@ -54,7 +54,7 @@ REGISTER_QUICK_ACTION( [&]() -> bool { return !CanFillGameTiles(); }, ALWAYS_FALSE, DEFAULT_BTN, - "Constructs game tiles from this layer") + "Constructs game tiles from this layer.") REGISTER_QUICK_ACTION( GameTilesFreeze, "Game tiles: Freeze", @@ -62,7 +62,7 @@ REGISTER_QUICK_ACTION( [&]() -> bool { return !CanFillGameTiles(); }, ALWAYS_FALSE, DEFAULT_BTN, - "Constructs game tiles from this layer") + "Constructs game tiles from this layer.") REGISTER_QUICK_ACTION( GameTilesUnfreeze, "Game tiles: Unfreeze", @@ -70,7 +70,7 @@ REGISTER_QUICK_ACTION( [&]() -> bool { return !CanFillGameTiles(); }, ALWAYS_FALSE, DEFAULT_BTN, - "Constructs game tiles from this layer") + "Constructs game tiles from this layer.") REGISTER_QUICK_ACTION( GameTilesDeepFreeze, "Game tiles: Deep Freeze", @@ -78,7 +78,7 @@ REGISTER_QUICK_ACTION( [&]() -> bool { return !CanFillGameTiles(); }, ALWAYS_FALSE, DEFAULT_BTN, - "Constructs game tiles from this layer") + "Constructs game tiles from this layer.") REGISTER_QUICK_ACTION( GameTilesDeepUnfreeze, "Game tiles: Deep Unfreeze", @@ -86,7 +86,7 @@ REGISTER_QUICK_ACTION( [&]() -> bool { return !CanFillGameTiles(); }, ALWAYS_FALSE, DEFAULT_BTN, - "Constructs game tiles from this layer") + "Constructs game tiles from this layer.") REGISTER_QUICK_ACTION( GameTilesBlueCheckTele, "Game tiles: Blue Check Tele", @@ -94,7 +94,7 @@ REGISTER_QUICK_ACTION( [&]() -> bool { return !CanFillGameTiles(); }, ALWAYS_FALSE, DEFAULT_BTN, - "Constructs game tiles from this layer") + "Constructs game tiles from this layer.") REGISTER_QUICK_ACTION( GameTilesRedCheckTele, "Game tiles: Red Check Tele", @@ -102,7 +102,7 @@ REGISTER_QUICK_ACTION( [&]() -> bool { return !CanFillGameTiles(); }, ALWAYS_FALSE, DEFAULT_BTN, - "Constructs game tiles from this layer") + "Constructs game tiles from this layer.") REGISTER_QUICK_ACTION( GameTilesLiveFreeze, "Game tiles: Live Freeze", @@ -110,7 +110,7 @@ REGISTER_QUICK_ACTION( [&]() -> bool { return !CanFillGameTiles(); }, ALWAYS_FALSE, DEFAULT_BTN, - "Constructs game tiles from this layer") + "Constructs game tiles from this layer.") REGISTER_QUICK_ACTION( GameTilesLiveUnfreeze, "Game tiles: Live Unfreeze", @@ -118,11 +118,23 @@ REGISTER_QUICK_ACTION( [&]() -> bool { return !CanFillGameTiles(); }, ALWAYS_FALSE, DEFAULT_BTN, - "Constructs game tiles from this layer") + "Constructs game tiles from this layer.") REGISTER_QUICK_ACTION( - AddGroup, "Add group", [&]() { AddGroup(); }, ALWAYS_FALSE, ALWAYS_FALSE, DEFAULT_BTN, "Adds a new group") + AddGroup, + "Add group", + [&]() { AddGroup(); }, + ALWAYS_FALSE, + ALWAYS_FALSE, + DEFAULT_BTN, + "Adds a new group.") REGISTER_QUICK_ACTION( - Refocus, "Refocus", [&]() { MapView()->Focus(); }, ALWAYS_FALSE, ALWAYS_FALSE, DEFAULT_BTN, "[HOME] Restore map focus") + Refocus, + "Refocus", + [&]() { MapView()->Focus(); }, + ALWAYS_FALSE, + ALWAYS_FALSE, + DEFAULT_BTN, + "[HOME] Restore map focus.") REGISTER_QUICK_ACTION( Proof, "Proof", @@ -140,7 +152,7 @@ REGISTER_QUICK_ACTION( ALWAYS_FALSE, ALWAYS_FALSE, DEFAULT_BTN, - "Saves the current map under a new name (ctrl+shift+s)") + "[Ctrl+Shift+S] Saves the current map under a new name.") REGISTER_QUICK_ACTION( LoadCurrentMap, "Load Current Map", @@ -158,7 +170,7 @@ REGISTER_QUICK_ACTION( ALWAYS_FALSE, ALWAYS_FALSE, DEFAULT_BTN, - "Opens the current in game map for editing (ctrl+alt+l)") + "[Ctrl+Alt+L] Opens the current in game map for editing.") REGISTER_QUICK_ACTION( Envelopes, "Envelopes", @@ -174,7 +186,7 @@ REGISTER_QUICK_ACTION( ALWAYS_FALSE, ALWAYS_FALSE, DEFAULT_BTN, - "Load a new image to use in the map") + "Load a new image to use in the map.") REGISTER_QUICK_ACTION( LayerPropAddImage, "Layer: Add Image", @@ -182,7 +194,7 @@ REGISTER_QUICK_ACTION( [&]() -> bool { return !IsNonGameTileLayerSelected(); }, ALWAYS_FALSE, DEFAULT_BTN, - "Pick mapres image for currently selected layer") + "Pick mapres image for currently selected layer.") REGISTER_QUICK_ACTION( ShowInfoOff, "Show Info: Off", @@ -193,7 +205,7 @@ REGISTER_QUICK_ACTION( ALWAYS_FALSE, [&]() -> bool { return m_ShowTileInfo == SHOW_TILE_OFF; }, DEFAULT_BTN, - "Do not show tile information") + "Do not show tile information.") REGISTER_QUICK_ACTION( ShowInfoDec, "Show Info: Dec", @@ -204,7 +216,7 @@ REGISTER_QUICK_ACTION( ALWAYS_FALSE, [&]() -> bool { return m_ShowTileInfo == SHOW_TILE_DECIMAL; }, DEFAULT_BTN, - "[ctrl+i] Show tile information") + "[Ctrl+I] Show tile information.") REGISTER_QUICK_ACTION( ShowInfoHex, "Show Info: Hex", @@ -215,7 +227,7 @@ REGISTER_QUICK_ACTION( ALWAYS_FALSE, [&]() -> bool { return m_ShowTileInfo == SHOW_TILE_HEXADECIMAL; }, DEFAULT_BTN, - "[ctrl+shift+i] Show tile information in hexadecimal") + "[Ctrl+Shift+I] Show tile information in hexadecimal.") #undef ALWAYS_FALSE #undef DEFAULT_BTN