From 1b47cf76d3801676d6266fee960b31f3acf234fc Mon Sep 17 00:00:00 2001 From: DavivaD Date: Thu, 2 Aug 2018 07:38:32 +0200 Subject: [PATCH 01/98] Implement Mod Manager --- src/CMakeLists.txt | 2 + src/app/app.cpp | 20 ++ src/app/app.h | 2 + src/app/pathman.cpp | 23 ++- src/app/pathman.h | 1 + src/common/event.cpp | 8 + src/common/event.h | 8 + src/common/restext.cpp | 8 + src/common/restext.h | 3 + src/graphics/engine/engine.h | 8 +- src/graphics/engine/text.cpp | 2 + src/level/robotmain.cpp | 1 + src/level/robotmain.h | 1 + src/ui/mainui.cpp | 7 +- src/ui/mainui.h | 2 + src/ui/screen/screen_setup.cpp | 24 ++- src/ui/screen/screen_setup_mods.cpp | 281 ++++++++++++++++++++++++++++ src/ui/screen/screen_setup_mods.h | 50 +++++ 18 files changed, 444 insertions(+), 7 deletions(-) create mode 100644 src/ui/screen/screen_setup_mods.cpp create mode 100644 src/ui/screen/screen_setup_mods.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c58172bd..1dd6edb1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -570,6 +570,8 @@ set(BASE_SOURCES ui/screen/screen_setup_game.h ui/screen/screen_setup_graphics.cpp ui/screen/screen_setup_graphics.h + ui/screen/screen_setup_mods.cpp + ui/screen/screen_setup_mods.h ui/screen/screen_setup_sound.cpp ui/screen/screen_setup_sound.h ui/screen/screen_welcome.cpp diff --git a/src/app/app.cpp b/src/app/app.cpp index 3444481c..ff8df246 100644 --- a/src/app/app.cpp +++ b/src/app/app.cpp @@ -699,6 +699,26 @@ bool CApplication::Create() return true; } +void CApplication::Reload() +{ + m_sound->Create(); + m_engine->ReloadAllTextures(); + CThread musicLoadThread([this]() + { + SystemTimeStamp* musicLoadStart = m_systemUtils->CreateTimeStamp(); + m_systemUtils->GetCurrentTimeStamp(musicLoadStart); + m_sound->CacheAll(); + SystemTimeStamp* musicLoadEnd = m_systemUtils->CreateTimeStamp(); + m_systemUtils->GetCurrentTimeStamp(musicLoadEnd); + float musicLoadTime = m_systemUtils->TimeStampDiff(musicLoadStart, musicLoadEnd, STU_MSEC); + GetLogger()->Debug("Sound loading took %.2f ms\n", musicLoadTime); + }, + "Sound loading thread"); + musicLoadThread.Start(); + m_controller->GetRobotMain()->UpdateCustomLevelList(); +} + + bool CApplication::CreateVideoSurface() { Uint32 videoFlags = SDL_WINDOW_OPENGL; diff --git a/src/app/app.h b/src/app/app.h index ccae3a5c..2a7cc67d 100644 --- a/src/app/app.h +++ b/src/app/app.h @@ -168,6 +168,8 @@ public: ParseArgsStatus ParseArguments(int argc, char *argv[]); //! Initializes the application bool Create(); + //! Reloads the application + void Reload(); //! Main event loop int Run(); //! Returns the code to be returned at main() exit diff --git a/src/app/pathman.cpp b/src/app/pathman.cpp index 60715ac1..26eebdf8 100644 --- a/src/app/pathman.cpp +++ b/src/app/pathman.cpp @@ -72,7 +72,28 @@ void CPathManager::AddModAutoloadDir(const std::string &modAutoloadDirPath) void CPathManager::AddMod(const std::string &modPath) { - m_mods.push_back(modPath); + std::string::size_type ON; + ON = modPath.find('~'); + if (ON == std::string::npos) + { + GetLogger()->Info("Loading mod: '%s'\n", modPath.c_str()); + m_mods.push_back(modPath); + } + else + { + GetLogger()->Info("Found Excluded mod: '%s'\n", modPath.c_str()); + } +} + +void CPathManager::RemoveMod(const std::string &modPath) +{ + std::string::size_type ON; + ON = modPath.find('~'); + if (ON == std::string::npos) + { + GetLogger()->Info("Unloading mod: '%s'\n", modPath.c_str()); + CResourceManager::RemoveLocation(modPath); + } } const std::string& CPathManager::GetDataPath() diff --git a/src/app/pathman.h b/src/app/pathman.h index dd18d66e..66dcae59 100644 --- a/src/app/pathman.h +++ b/src/app/pathman.h @@ -39,6 +39,7 @@ public: void SetSavePath(const std::string &savePath); void AddModAutoloadDir(const std::string &modAutoloadDirPath); void AddMod(const std::string &modPath); + void RemoveMod(const std::string &modPath); const std::string& GetDataPath(); const std::string& GetLangPath(); diff --git a/src/common/event.cpp b/src/common/event.cpp index 8dded9e1..7ceea30e 100644 --- a/src/common/event.cpp +++ b/src/common/event.cpp @@ -196,6 +196,7 @@ void InitializeEventTypeTexts() EVENT_TYPE_TEXT[EVENT_INTERFACE_SETUPp] = "EVENT_INTERFACE_SETUPp"; EVENT_TYPE_TEXT[EVENT_INTERFACE_SETUPc] = "EVENT_INTERFACE_SETUPc"; EVENT_TYPE_TEXT[EVENT_INTERFACE_SETUPs] = "EVENT_INTERFACE_SETUPs"; + EVENT_TYPE_TEXT[EVENT_INTERFACE_SETUPm] = "EVENT_INTERFACE_SETUPm"; EVENT_TYPE_TEXT[EVENT_INTERFACE_DEVICE] = "EVENT_INTERFACE_DEVICE"; EVENT_TYPE_TEXT[EVENT_INTERFACE_RESOL] = "EVENT_INTERFACE_RESOL"; @@ -265,6 +266,13 @@ void InitializeEventTypeTexts() EVENT_TYPE_TEXT[EVENT_INTERFACE_JOYSTICK_CAM_Y_INVERT]= "EVENT_INTERFACE_JOYSTICK_CAM_Y_INVERT"; EVENT_TYPE_TEXT[EVENT_INTERFACE_JOYSTICK_CAM_Z_INVERT]= "EVENT_INTERFACE_JOYSTICK_CAM_Z_INVERT"; + EVENT_TYPE_TEXT[EVENT_INTERFACE_MODS_UNLOADED] = "EVENT_INTERFACE_MODS_UNLOADED"; + EVENT_TYPE_TEXT[EVENT_INTERFACE_MODS_LOADED] = "EVENT_INTERFACE_MODS_LOADED"; + EVENT_TYPE_TEXT[EVENT_INTERFACE_WORKSHOP] = "EVENT_INTERFACE_WORKSHOP"; + EVENT_TYPE_TEXT[EVENT_INTERFACE_MODS_DIR] = "EVENT_INTERFACE_MODS_DIR"; + EVENT_TYPE_TEXT[EVENT_INTERFACE_LOAD] = "EVENT_INTERFACE_LOAD"; + EVENT_TYPE_TEXT[EVENT_INTERFACE_UNLOAD] = "EVENT_INTERFACE_UNLOAD"; + EVENT_TYPE_TEXT[EVENT_INTERFACE_GLINTl] = "EVENT_INTERFACE_GLINTl"; EVENT_TYPE_TEXT[EVENT_INTERFACE_GLINTr] = "EVENT_INTERFACE_GLINTr"; EVENT_TYPE_TEXT[EVENT_INTERFACE_GLINTu] = "EVENT_INTERFACE_GLINTu"; diff --git a/src/common/event.h b/src/common/event.h index 64c52e41..faabfd9f 100644 --- a/src/common/event.h +++ b/src/common/event.h @@ -231,6 +231,7 @@ enum EventType EVENT_INTERFACE_SETUPp = 432, EVENT_INTERFACE_SETUPc = 433, EVENT_INTERFACE_SETUPs = 434, + EVENT_INTERFACE_SETUPm = 435, EVENT_INTERFACE_DEVICE = 440, EVENT_INTERFACE_RESOL = 441, @@ -304,6 +305,13 @@ enum EventType EVENT_INTERFACE_JOYSTICK_CAM_Y_INVERT = 573, EVENT_INTERFACE_JOYSTICK_CAM_Z_INVERT = 574, + EVENT_INTERFACE_MODS_UNLOADED = 580, + EVENT_INTERFACE_MODS_LOADED = 581, + EVENT_INTERFACE_WORKSHOP = 582, + EVENT_INTERFACE_MODS_DIR = 583, + EVENT_INTERFACE_LOAD = 584, + EVENT_INTERFACE_UNLOAD = 585, + EVENT_INTERFACE_GLINTl = 590, EVENT_INTERFACE_GLINTr = 591, EVENT_INTERFACE_GLINTu = 592, diff --git a/src/common/restext.cpp b/src/common/restext.cpp index 9bac8434..ac664d58 100644 --- a/src/common/restext.cpp +++ b/src/common/restext.cpp @@ -89,6 +89,9 @@ void InitializeRestext() stringsText[RT_SETUP_KEY1] = TR("1) First click on the key you want to redefine."); stringsText[RT_SETUP_KEY2] = TR("2) Then press the key you want to use instead."); + stringsText[RT_MODS_UNLOADED] = TR("Unloaded Mods:"); + stringsText[RT_MODS_LOADED] = TR("Loaded Mods:"); + stringsText[RT_PERSO_FACE] = TR("Face type:"); stringsText[RT_PERSO_GLASSES] = TR("Eyeglasses:"); stringsText[RT_PERSO_HAIR] = TR("Hair color:"); @@ -176,11 +179,16 @@ void InitializeRestext() stringsEvent[EVENT_INTERFACE_QUIT] = TR("Quit\\Quit Colobot: Gold Edition"); stringsEvent[EVENT_INTERFACE_BACK] = TR("<< Back \\Back to the previous screen"); stringsEvent[EVENT_INTERFACE_PLAY] = TR("Play\\Start mission!"); + stringsEvent[EVENT_INTERFACE_WORKSHOP] = TR("Workshop\\Open Workshop to search Mods"); + stringsEvent[EVENT_INTERFACE_MODS_DIR] = TR("Open Directory\\Open Mods directory"); + stringsEvent[EVENT_INTERFACE_LOAD] = TR("Load\\Load Mod"); + stringsEvent[EVENT_INTERFACE_UNLOAD] = TR("Unload\\Unload Mod"); stringsEvent[EVENT_INTERFACE_SETUPd] = TR("Device\\Driver and resolution settings"); stringsEvent[EVENT_INTERFACE_SETUPg] = TR("Graphics\\Graphics settings"); stringsEvent[EVENT_INTERFACE_SETUPp] = TR("Game\\Game settings"); stringsEvent[EVENT_INTERFACE_SETUPc] = TR("Controls\\Keyboard, joystick and mouse settings"); stringsEvent[EVENT_INTERFACE_SETUPs] = TR("Sound\\Music and game sound volume"); + stringsEvent[EVENT_INTERFACE_SETUPm] = TR("Mods\\Manage installed mods"); stringsEvent[EVENT_INTERFACE_DEVICE] = TR("Unit"); stringsEvent[EVENT_INTERFACE_RESOL] = TR("Resolution"); stringsEvent[EVENT_INTERFACE_FULL] = TR("Full screen\\Full screen or window mode"); diff --git a/src/common/restext.h b/src/common/restext.h index 6acfb610..81cff850 100644 --- a/src/common/restext.h +++ b/src/common/restext.h @@ -86,6 +86,9 @@ enum ResTextType RT_SETUP_KEY1 = 82, RT_SETUP_KEY2 = 83, + RT_MODS_UNLOADED = 85, + RT_MODS_LOADED = 86, + RT_PERSO_FACE = 90, RT_PERSO_GLASSES = 91, RT_PERSO_HAIR = 92, diff --git a/src/graphics/engine/engine.h b/src/graphics/engine/engine.h index 794bd9e8..10fa04f4 100644 --- a/src/graphics/engine/engine.h +++ b/src/graphics/engine/engine.h @@ -1182,6 +1182,10 @@ public: void EnablePauseBlur(); void DisablePauseBlur(); + //! Reloads all textures + /** This additionally sends EVENT_RELOAD_TEXTURES to reload all textures not maintained by CEngine **/ + void ReloadAllTextures(); + protected: //! Resets some states and flushes textures after device was changed (e.g. resoulution changed) /** Instead of calling this directly, send EVENT_RESOLUTION_CHANGED event **/ @@ -1280,10 +1284,6 @@ protected: }; static void WriteScreenShotThread(std::unique_ptr data); - //! Reloads all textures - /** This additionally sends EVENT_RELOAD_TEXTURES to reload all textures not maintained by CEngine **/ - void ReloadAllTextures(); - protected: CApplication* m_app; CSystemUtils* m_systemUtils; diff --git a/src/graphics/engine/text.cpp b/src/graphics/engine/text.cpp index a16439f4..c930db8e 100644 --- a/src/graphics/engine/text.cpp +++ b/src/graphics/engine/text.cpp @@ -261,6 +261,8 @@ void CText::FlushCache() m_lastCachedFont = nullptr; m_lastFontType = FONT_COMMON; m_lastFontSize = 0; + + Create(); } int CText::GetTabSize() diff --git a/src/level/robotmain.cpp b/src/level/robotmain.cpp index 3bf3e2d5..14e26f9e 100644 --- a/src/level/robotmain.cpp +++ b/src/level/robotmain.cpp @@ -321,6 +321,7 @@ std::string PhaseToString(Phase phase) if (phase == PHASE_SETUPp) return "PHASE_SETUPp"; if (phase == PHASE_SETUPc) return "PHASE_SETUPc"; if (phase == PHASE_SETUPs) return "PHASE_SETUPs"; + if (phase == PHASE_SETUPm) return "PHASE_SETUPm"; if (phase == PHASE_SETUPds) return "PHASE_SETUPds"; if (phase == PHASE_SETUPgs) return "PHASE_SETUPgs"; if (phase == PHASE_SETUPps) return "PHASE_SETUPps"; diff --git a/src/level/robotmain.h b/src/level/robotmain.h index 2614f2cc..68768beb 100644 --- a/src/level/robotmain.h +++ b/src/level/robotmain.h @@ -61,6 +61,7 @@ enum Phase PHASE_SETUPp, PHASE_SETUPc, PHASE_SETUPs, + PHASE_SETUPm, PHASE_SETUPds, PHASE_SETUPgs, PHASE_SETUPps, diff --git a/src/ui/mainui.cpp b/src/ui/mainui.cpp index 2ffb17fe..7e63a7db 100644 --- a/src/ui/mainui.cpp +++ b/src/ui/mainui.cpp @@ -53,6 +53,7 @@ #include "ui/screen/screen_setup_display.h" #include "ui/screen/screen_setup_game.h" #include "ui/screen/screen_setup_graphics.h" +#include "ui/screen/screen_setup_mods.h" #include "ui/screen/screen_setup_sound.h" #include "ui/screen/screen_welcome.h" @@ -82,6 +83,7 @@ CMainUserInterface::CMainUserInterface() m_screenSetupDisplay = MakeUnique(); m_screenSetupGame = MakeUnique(); m_screenSetupGraphics = MakeUnique(); + m_screenSetupMods = MakeUnique(); m_screenSetupSound = MakeUnique(); m_screenMainMenu = MakeUnique(); m_screenPlayerSelect = MakeUnique(m_dialog.get()); @@ -142,6 +144,7 @@ CScreenSetup* CMainUserInterface::GetSetupScreen(Phase phase) if(phase == PHASE_SETUPp) return m_screenSetupGame.get(); if(phase == PHASE_SETUPc) return m_screenSetupControls.get(); if(phase == PHASE_SETUPs) return m_screenSetupSound.get(); + if(phase == PHASE_SETUPm) return m_screenSetupMods.get(); assert(false); return nullptr; } @@ -182,7 +185,7 @@ void CMainUserInterface::ChangePhase(Phase phase) m_screenLevelList->SetLevelCategory(m_main->GetLevelCategory()); m_currentScreen = m_screenLevelList.get(); } - if (m_phase >= PHASE_SETUPd && m_phase <= PHASE_SETUPs) + if (m_phase >= PHASE_SETUPd && m_phase <= PHASE_SETUPm) { CScreenSetup* screenSetup = GetSetupScreen(m_phase); screenSetup->SetInSimulation(false); @@ -345,6 +348,7 @@ void CMainUserInterface::GlintMove() m_phase == PHASE_SETUPp || m_phase == PHASE_SETUPc || m_phase == PHASE_SETUPs || + m_phase == PHASE_SETUPm || m_phase == PHASE_SETUPds || m_phase == PHASE_SETUPgs || m_phase == PHASE_SETUPps || @@ -534,6 +538,7 @@ void CMainUserInterface::FrameParticle(float rTime) m_phase == PHASE_SETUPp || m_phase == PHASE_SETUPc || m_phase == PHASE_SETUPs || + m_phase == PHASE_SETUPm || m_phase == PHASE_READ ) { pParti = partiPosBig; diff --git a/src/ui/mainui.h b/src/ui/mainui.h index 77074492..0d3ce91e 100644 --- a/src/ui/mainui.h +++ b/src/ui/mainui.h @@ -55,6 +55,7 @@ class CScreenSetupControls; class CScreenSetupDisplay; class CScreenSetupGame; class CScreenSetupGraphics; +class CScreenSetupMods; class CScreenSetupSound; class CScreenWelcome; @@ -119,6 +120,7 @@ protected: std::unique_ptr m_screenSetupDisplay; std::unique_ptr m_screenSetupGame; std::unique_ptr m_screenSetupGraphics; + std::unique_ptr m_screenSetupMods; std::unique_ptr m_screenSetupSound; std::unique_ptr m_screenWelcome; diff --git a/src/ui/screen/screen_setup.cpp b/src/ui/screen/screen_setup.cpp index 823207af..e9c36a71 100644 --- a/src/ui/screen/screen_setup.cpp +++ b/src/ui/screen/screen_setup.cpp @@ -83,7 +83,7 @@ void CScreenSetup::CreateInterface() ddim.y = 0.05f; pw->CreateGroup(pos, ddim, 3, EVENT_NULL); // transparent -> gray - ddim.x = 0.78f/5-0.01f; + ddim.x = 0.65f/5-0.01f; ddim.y = 0.06f; pos.x = 0.115f; pos.y = 0.76f; @@ -116,6 +116,12 @@ void CScreenSetup::CreateInterface() pb->SetState(STATE_CARD); pb->SetState(STATE_CHECK, (m_tab == PHASE_SETUPs)); + pos.x += ddim.x+0.01f; + pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_SETUPm); + pb->SetState(STATE_SHADOW); + pb->SetState(STATE_CARD); + pb->SetState(STATE_CHECK, (m_tab == PHASE_SETUPm)); + pos.x = 0.10f; ddim.x = 0.80f; pos.y = 0.34f; @@ -148,6 +154,10 @@ bool CScreenSetup::EventProcess(const Event &event) CWindow* pw = static_cast(m_interface->SearchControl(EVENT_WINDOW5)); if ( pw == nullptr ) return false; + CButton* pb = static_cast(pw->SearchControl(EVENT_INTERFACE_SETUPm)); + if ( pb == nullptr ) return false; + pb->SetState(STATE_ENABLE); + if ( event.type == pw->GetEventTypeClose() || event.type == EVENT_INTERFACE_BACK || (event.type == EVENT_KEY_DOWN && event.GetData()->key == KEY(ESCAPE)) ) @@ -179,6 +189,10 @@ bool CScreenSetup::EventProcess(const Event &event) m_main->ChangePhase(PHASE_SETUPs); return false; + case EVENT_INTERFACE_SETUPm: + m_main->ChangePhase(PHASE_SETUPm); + return false; + default: break; } @@ -188,6 +202,10 @@ bool CScreenSetup::EventProcess(const Event &event) CWindow* pw = static_cast(m_interface->SearchControl(EVENT_WINDOW5)); if ( pw == nullptr ) return false; + CButton* pb = static_cast(pw->SearchControl(EVENT_INTERFACE_SETUPm)); + if ( pb == nullptr ) return false; + pb->ClearState(STATE_ENABLE); + if ( event.type == pw->GetEventTypeClose() || event.type == EVENT_INTERFACE_BACK || (event.type == EVENT_KEY_DOWN && event.GetData()->key == KEY(ESCAPE)) ) @@ -221,6 +239,10 @@ bool CScreenSetup::EventProcess(const Event &event) m_main->ChangePhase(PHASE_SETUPss); return false; + case EVENT_INTERFACE_SETUPm: + m_main->ChangePhase(PHASE_SETUPm); + return false; + default: break; } diff --git a/src/ui/screen/screen_setup_mods.cpp b/src/ui/screen/screen_setup_mods.cpp new file mode 100644 index 00000000..960d7e21 --- /dev/null +++ b/src/ui/screen/screen_setup_mods.cpp @@ -0,0 +1,281 @@ +/* + * This file is part of the Colobot: Gold Edition source code + * Copyright (C) 2001-2018, Daniel Roux, EPSITEC SA & TerranovaTeam + * http://epsitec.ch; http://colobot.info; http://github.com/colobot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#include "ui/screen/screen_setup_mods.h" + +#include "app/app.h" +#include "app/pathman.h" + +#include "common/restext.h" +#include "common/config.h" +#include "common/logger.h" +#include "common/settings.h" + +#include "common/resources/resourcemanager.h" +#include "level/parser/parser.h" + +#include "ui/controls/button.h" +#include "ui/controls/edit.h" +#include "ui/controls/interface.h" +#include "ui/controls/label.h" +#include "ui/controls/list.h" +#include "ui/controls/window.h" + +#include +#include + +namespace Ui +{ + +CScreenSetupMods::CScreenSetupMods() +{ +} + +void CScreenSetupMods::SetActive() +{ + m_tab = PHASE_SETUPm; +} + +void CScreenSetupMods::CreateInterface() +{ + CWindow* pw; + CLabel* pl; + CButton* pb; + CList* pli; + Math::Point pos, ddim; + std::string name; + + CScreenSetup::CreateInterface(); + pw = static_cast(m_interface->SearchControl(EVENT_WINDOW5)); + if ( pw == nullptr ) return; + + // Displays a list of unloaded mods: + pos.x = ox+sx*3; + pos.y = oy+sy*9; + ddim.x = dim.x*6; + ddim.y = dim.y*1; + GetResource(RES_TEXT, RT_MODS_UNLOADED, name); + pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL11, name); + pl->SetTextAlign(Gfx::TEXT_ALIGN_LEFT); + + pos.y = oy+sy*3.75f; + ddim.x = dim.x*6.5f; + ddim.y = dim.y*6.05f; + pli = pw->CreateList(pos, ddim, 0, EVENT_INTERFACE_MODS_UNLOADED); + pli->SetState(STATE_SHADOW); + UpdateUnloadedModList(); + + // Displays a list of loaded mods: + pos.x = ox+sx*9.5f; + pos.y = oy+sy*9; + ddim.x = dim.x*6; + ddim.y = dim.y*1; + GetResource(RES_TEXT, RT_MODS_LOADED, name); + pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL12, name); + pl->SetTextAlign(Gfx::TEXT_ALIGN_LEFT); + + pos.y = oy+sy*3.75f; + ddim.x = dim.x*6.5f; + ddim.y = dim.y*6.05f; + pli = pw->CreateList(pos, ddim, 0, EVENT_INTERFACE_MODS_LOADED); + pli->SetState(STATE_SHADOW); + UpdateLoadedModList(); + + pos = pli->GetPos(); + ddim = pli->GetDim(); + pos.x = ox+sx*8.2f; + pos.y = oy+sy*2; + ddim.x = dim.x*1; + ddim.y = dim.y*1; + pb = pw->CreateButton(pos, ddim, 40, EVENT_INTERFACE_WORKSHOP); + pb->SetState(STATE_SHADOW); + + pos.x += dim.x*1.3f; + pb = pw->CreateButton(pos, ddim, 57, EVENT_INTERFACE_MODS_DIR); + pb->SetState(STATE_SHADOW); + + pos.x += dim.x*1.3f; + ddim.x = dim.x*2.5f; + pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_LOAD); + pb->SetState(STATE_SHADOW); + pb->ClearState(STATE_ENABLE); + + pos.x += dim.x*2.8f; + pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_UNLOAD); + pb->SetState(STATE_SHADOW); + pb->ClearState(STATE_ENABLE); +} +bool CScreenSetupMods::EventProcess(const Event &event) +{ + CWindow* pw; + CButton* pb; + CList* pl; + int result; + std::string modName, modPath, modPathRaw, OFF = "~"; + + if (!CScreenSetup::EventProcess(event)) return false; + + pw = static_cast(m_interface->SearchControl(EVENT_WINDOW5)); + if ( pw == nullptr ) return false; + + if (event.type == EVENT_INTERFACE_LOAD) + { + pl = static_cast(pw->SearchControl(EVENT_INTERFACE_MODS_UNLOADED)); + if ( pl == nullptr ) return false; + modName = pl->GetItemName(pl->GetSelect()); + + modPathRaw = CResourceManager::GetSaveLocation() + "/" + "mods" + "/"; + modPath = modPathRaw.c_str(); + boost::filesystem::rename(modPath+OFF+modName, modPath+modName); + m_pathManager->AddMod(modPath+modName); + m_app->Reload(); + m_main->ChangePhase(PHASE_SETUPm); + } + if (event.type == EVENT_INTERFACE_UNLOAD) + { + pl = static_cast(pw->SearchControl(EVENT_INTERFACE_MODS_LOADED)); + if ( pl == nullptr ) return false; + modName = pl->GetItemName(pl->GetSelect()); + + modPathRaw = CResourceManager::GetSaveLocation() + "/" + "mods" + "/"; + modPath = modPathRaw.c_str(); + m_pathManager->RemoveMod(modPath+modName); + boost::filesystem::rename(modPath+modName, modPath+OFF+modName); + m_app->Reload(); + m_main->ChangePhase(PHASE_SETUPm); + } + if (event.type == EVENT_INTERFACE_MODS_DIR) + { + modPathRaw = CResourceManager::GetSaveLocation() + "/" + "mods"; + #if defined(PLATFORM_WINDOWS) + result = system(("start \""+modPathRaw+"\"").c_str()); + #elif defined(PLATFORM_LINUX) + result = system(("xdg-open \""+modPathRaw+"\"").c_str()); + #elif defined(PLATFORM_MACOSX) + result = system(("open \""+modPathRaw+"\"").c_str()); + #endif + if (result == -1) + { + GetLogger()->Error("Failed to open Mods directory! Does directory exists?\n"); + } + } + switch (event.type) + { + case EVENT_INTERFACE_MODS_UNLOADED: + pl = static_cast(pw->SearchControl(EVENT_INTERFACE_MODS_LOADED)); + if ( pl == nullptr ) break; + + pb = static_cast(pw->SearchControl(EVENT_INTERFACE_UNLOAD)); + if ( pb == nullptr ) break; + pl->SetSelect(-1); + pb->ClearState(STATE_ENABLE); + + pb = static_cast(pw->SearchControl(EVENT_INTERFACE_LOAD)); + if ( pb == nullptr ) break; + pb->SetState(STATE_ENABLE); + break; + + case EVENT_INTERFACE_MODS_LOADED: + pl = static_cast(pw->SearchControl(EVENT_INTERFACE_MODS_UNLOADED)); + if ( pl == nullptr ) break; + + pb = static_cast(pw->SearchControl(EVENT_INTERFACE_LOAD)); + if ( pb == nullptr ) break; + pl->SetSelect(-1); + pb->ClearState(STATE_ENABLE); + + pb = static_cast(pw->SearchControl(EVENT_INTERFACE_UNLOAD)); + if ( pb == nullptr ) break; + pb->SetState(STATE_ENABLE); + break; + + case EVENT_INTERFACE_WORKSHOP: + #if defined(PLATFORM_WINDOWS) + result = system("start \"https://colobot.info/forum/forumdisplay.php?fid=60\""); + #elif defined(PLATFORM_LINUX) + result = system("xdg-open \"https://colobot.info/forum/forumdisplay.php?fid=60\""); + #elif defined(PLATFORM_MACOSX) + result = system("open \"https://colobot.info/forum/forumdisplay.php?fid=60\""); + #endif + if (result == -1) + { + GetLogger()->Error("Failed to open Workshop page! Is any Web Broswer installed?\n"); + } + break; + default: + return true; + } + return false; +} +void CScreenSetupMods::UpdateUnloadedModList() +{ + CWindow* pw; + CList* pl; + int i = 0; + std::string modName; + + pw = static_cast(m_interface->SearchControl(EVENT_WINDOW5)); + if ( pw == nullptr ) return; + + pl = static_cast(pw->SearchControl(EVENT_INTERFACE_MODS_UNLOADED)); + if ( pl == nullptr ) return; + pl->Flush(); + + auto modsDir = CResourceManager::ListDirectories("mods/"); + std::sort(modsDir.begin(), modsDir.end()); + + for(auto const& modNameRaw : modsDir) + { + modName = modNameRaw; + std::string::size_type ON; + ON = modName.find('~'); + if (ON != std::string::npos) + { + modName.erase(0,1); + pl->SetItemName(i++, modName); + } + } + pl->ShowSelect(false); // shows the selected columns +} +void CScreenSetupMods::UpdateLoadedModList() +{ + CWindow* pw; + CList* pl; + int i = 0; + + pw = static_cast(m_interface->SearchControl(EVENT_WINDOW5)); + if ( pw == nullptr ) return; + + pl = static_cast(pw->SearchControl(EVENT_INTERFACE_MODS_LOADED)); + if ( pl == nullptr ) return; + pl->Flush(); + + auto modsDir = CResourceManager::ListDirectories("mods/"); + std::sort(modsDir.begin(), modsDir.end()); + + for(auto const &modName : modsDir) + { + std::string::size_type ON; + ON = modName.find('~'); + if (ON == std::string::npos) + pl->SetItemName(i++, modName); + } + pl->ShowSelect(false); // shows the selected columns +} +} // namespace Ui diff --git a/src/ui/screen/screen_setup_mods.h b/src/ui/screen/screen_setup_mods.h new file mode 100644 index 00000000..0d54502f --- /dev/null +++ b/src/ui/screen/screen_setup_mods.h @@ -0,0 +1,50 @@ +/* + * This file is part of the Colobot: Gold Edition source code + * Copyright (C) 2001-2018, Daniel Roux, EPSITEC SA & TerranovaTeam + * http://epsitec.ch; http://colobot.info; http://github.com/colobot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#pragma once + +#include "ui/screen/screen_setup.h" + +#include + +class CPathManager; + +namespace Ui +{ + +class CScreenSetupMods : public CScreenSetup +{ +public: + CScreenSetupMods(); + void SetActive() override; + + void CreateInterface() override; + bool EventProcess(const Event &event) override; + +protected: + void UpdateUnloadedModList(); + void UpdateLoadedModList(); + +protected: + CPathManager* m_pathManager; + std::vector m_unloadedModList; + std::vector m_loadedModList; +}; + +} // namespace Ui From e823c209faf2084dca8aacc73d8b223b955f27f9 Mon Sep 17 00:00:00 2001 From: DavivaD Date: Thu, 2 Aug 2018 17:21:31 +0200 Subject: [PATCH 02/98] Fix crash while loading mod and blank settings menu while paused game --- src/app/pathman.cpp | 30 ++++++++++++++++++++++++------ src/level/robotmain.cpp | 4 +++- src/level/robotmain.h | 1 + src/ui/maindialog.cpp | 1 + src/ui/mainui.cpp | 2 +- src/ui/screen/screen_setup.cpp | 1 - 6 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/app/pathman.cpp b/src/app/pathman.cpp index 26eebdf8..9656d3eb 100644 --- a/src/app/pathman.cpp +++ b/src/app/pathman.cpp @@ -77,11 +77,11 @@ void CPathManager::AddMod(const std::string &modPath) if (ON == std::string::npos) { GetLogger()->Info("Loading mod: '%s'\n", modPath.c_str()); - m_mods.push_back(modPath); + CResourceManager::AddLocation(modPath, true); } else { - GetLogger()->Info("Found Excluded mod: '%s'\n", modPath.c_str()); + GetLogger()->Info("Found excluded mod: '%s'\n", modPath.c_str()); } } @@ -171,15 +171,33 @@ void CPathManager::InitPaths() GetLogger()->Trace("Searching for mods in '%s'...\n", modAutoloadDir.c_str()); for (const std::string& modPath : FindModsInDir(modAutoloadDir)) { - GetLogger()->Info("Autoloading mod: '%s'\n", modPath.c_str()); - CResourceManager::AddLocation(modPath); + std::string::size_type ON; + ON = modPath.find('~'); + if (ON == std::string::npos) + { + GetLogger()->Info("Autoloading mod: '%s'\n", modPath.c_str()); + CResourceManager::AddLocation(modPath); + } + else + { + GetLogger()->Info("Found excluded mod: '%s'\n", modPath.c_str()); + } } } for (const std::string& modPath : m_mods) { - GetLogger()->Info("Loading mod: '%s'\n", modPath.c_str()); - CResourceManager::AddLocation(modPath); + std::string::size_type ON; + ON = modPath.find('~'); + if (ON == std::string::npos) + { + GetLogger()->Info("Loading mod: '%s'\n", modPath.c_str()); + CResourceManager::AddLocation(modPath); + } + else + { + GetLogger()->Info("Found excluded mod: '%s'\n", modPath.c_str()); + } } CResourceManager::SetSaveLocation(m_savePath); diff --git a/src/level/robotmain.cpp b/src/level/robotmain.cpp index 14e26f9e..14397feb 100644 --- a/src/level/robotmain.cpp +++ b/src/level/robotmain.cpp @@ -327,6 +327,7 @@ std::string PhaseToString(Phase phase) if (phase == PHASE_SETUPps) return "PHASE_SETUPps"; if (phase == PHASE_SETUPcs) return "PHASE_SETUPcs"; if (phase == PHASE_SETUPss) return "PHASE_SETUPss"; + if (phase == PHASE_SETUPms) return "PHASE_SETUPms"; if (phase == PHASE_WRITEs) return "PHASE_WRITEs"; if (phase == PHASE_READ) return "PHASE_READ"; if (phase == PHASE_READs) return "PHASE_READs"; @@ -339,7 +340,7 @@ std::string PhaseToString(Phase phase) bool IsInSimulationConfigPhase(Phase phase) { - return (phase >= PHASE_SETUPds && phase <= PHASE_SETUPss) || phase == PHASE_READs || phase == PHASE_WRITEs; + return (phase >= PHASE_SETUPds && phase <= PHASE_SETUPms) || phase == PHASE_READs || phase == PHASE_WRITEs; } bool IsPhaseWithWorld(Phase phase) @@ -3865,6 +3866,7 @@ void CRobotMain::ChangeColor() m_phase != PHASE_SETUPps && m_phase != PHASE_SETUPcs && m_phase != PHASE_SETUPss && + m_phase != PHASE_SETUPms && m_phase != PHASE_WIN && m_phase != PHASE_LOST && m_phase != PHASE_APPERANCE ) return; diff --git a/src/level/robotmain.h b/src/level/robotmain.h index 68768beb..cd3345e4 100644 --- a/src/level/robotmain.h +++ b/src/level/robotmain.h @@ -67,6 +67,7 @@ enum Phase PHASE_SETUPps, PHASE_SETUPcs, PHASE_SETUPss, + PHASE_SETUPms, PHASE_WRITEs, PHASE_READ, PHASE_READs, diff --git a/src/ui/maindialog.cpp b/src/ui/maindialog.cpp index 01d87dc2..395a875e 100644 --- a/src/ui/maindialog.cpp +++ b/src/ui/maindialog.cpp @@ -107,6 +107,7 @@ bool CMainDialog::EventProcess(const Event &event) if ( CScreenSetup::GetTab() == PHASE_SETUPp ) m_main->ChangePhase(PHASE_SETUPps); if ( CScreenSetup::GetTab() == PHASE_SETUPc ) m_main->ChangePhase(PHASE_SETUPcs); if ( CScreenSetup::GetTab() == PHASE_SETUPs ) m_main->ChangePhase(PHASE_SETUPss); + if ( CScreenSetup::GetTab() == PHASE_SETUPm ) m_main->ChangePhase(PHASE_SETUPss); } if ( pressedButton == EVENT_INTERFACE_WRITE ) diff --git a/src/ui/mainui.cpp b/src/ui/mainui.cpp index 7e63a7db..1ca364bc 100644 --- a/src/ui/mainui.cpp +++ b/src/ui/mainui.cpp @@ -192,7 +192,7 @@ void CMainUserInterface::ChangePhase(Phase phase) screenSetup->SetActive(); m_currentScreen = screenSetup; } - if (m_phase >= PHASE_SETUPds && m_phase <= PHASE_SETUPss) + if (m_phase >= PHASE_SETUPds && m_phase <= PHASE_SETUPms) { CScreenSetup* screenSetup = GetSetupScreen(static_cast(m_phase - PHASE_SETUPds + PHASE_SETUPd)); screenSetup->SetInSimulation(true); diff --git a/src/ui/screen/screen_setup.cpp b/src/ui/screen/screen_setup.cpp index e9c36a71..3dbc0836 100644 --- a/src/ui/screen/screen_setup.cpp +++ b/src/ui/screen/screen_setup.cpp @@ -240,7 +240,6 @@ bool CScreenSetup::EventProcess(const Event &event) return false; case EVENT_INTERFACE_SETUPm: - m_main->ChangePhase(PHASE_SETUPm); return false; default: From e9a153df14d5223397e72690dc85cfae75aac5b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20G=C3=B6ttlicher?= Date: Sun, 28 Apr 2019 01:27:12 +0200 Subject: [PATCH 03/98] Smoother shadows on OpenGL 2.1 --- src/graphics/opengl/gl21device.cpp | 3 +++ src/graphics/opengl/glutil.h | 2 ++ src/graphics/opengl/shaders/gl21/fs_normal.glsl | 11 +++++------ 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/graphics/opengl/gl21device.cpp b/src/graphics/opengl/gl21device.cpp index 41660578..6feaf1c4 100644 --- a/src/graphics/opengl/gl21device.cpp +++ b/src/graphics/opengl/gl21device.cpp @@ -408,6 +408,7 @@ bool CGL21Device::Create() uni.fogColor = glGetUniformLocation(m_normalProgram, "uni_FogColor"); uni.shadowColor = glGetUniformLocation(m_normalProgram, "uni_ShadowColor"); + uni.shadowTexelSize = glGetUniformLocation(m_normalProgram, "uni_ShadowTexelSize"); uni.lightCount = glGetUniformLocation(m_normalProgram, "uni_LightCount"); uni.ambientColor = glGetUniformLocation(m_normalProgram, "uni_Material.ambient"); @@ -457,6 +458,7 @@ bool CGL21Device::Create() glUniform4f(uni.fogColor, 0.8f, 0.8f, 0.8f, 1.0f); glUniform1f(uni.shadowColor, 0.5f); + glUniform1f(uni.shadowTexelSize, 0.5f); glUniform1i(uni.lightCount, 0); } @@ -1439,6 +1441,7 @@ void CGL21Device::SetRenderState(RenderState state, bool enabled) } else if (state == RENDER_STATE_SHADOW_MAPPING) { + glUniform1f(m_uniforms[m_mode].shadowTexelSize, 1.0/m_currentTextures[TEXTURE_SHADOW].size.x); SetTextureEnabled(TEXTURE_SHADOW, enabled); return; diff --git a/src/graphics/opengl/glutil.h b/src/graphics/opengl/glutil.h index 977bc9c3..2ebb3feb 100644 --- a/src/graphics/opengl/glutil.h +++ b/src/graphics/opengl/glutil.h @@ -193,6 +193,8 @@ struct UniformLocations //! Shadow color GLint shadowColor = -1; + //! Shadow texel size + GLint shadowTexelSize = -1; // Number of enabled lights GLint lightCount = -1; diff --git a/src/graphics/opengl/shaders/gl21/fs_normal.glsl b/src/graphics/opengl/shaders/gl21/fs_normal.glsl index d21bc9cf..10a07289 100644 --- a/src/graphics/opengl/shaders/gl21/fs_normal.glsl +++ b/src/graphics/opengl/shaders/gl21/fs_normal.glsl @@ -35,6 +35,7 @@ uniform vec2 uni_FogRange; uniform vec4 uni_FogColor; uniform float uni_ShadowColor; +uniform float uni_ShadowTexelSize; struct LightParams { @@ -97,13 +98,11 @@ void main() if (uni_TextureEnabled[2]) { #ifdef CONFIG_QUALITY_SHADOWS - float offset = 0.00025f; - float value = (1.0f / 5.0f) * (shadow2D(uni_ShadowTexture, pass_TexCoord2).x - + shadow2D(uni_ShadowTexture, pass_TexCoord2 + vec3( offset, 0.0f, 0.0f)).x - + shadow2D(uni_ShadowTexture, pass_TexCoord2 + vec3(-offset, 0.0f, 0.0f)).x - + shadow2D(uni_ShadowTexture, pass_TexCoord2 + vec3( 0.0f, offset, 0.0f)).x - + shadow2D(uni_ShadowTexture, pass_TexCoord2 + vec3( 0.0f, -offset, 0.0f)).x); + + shadow2D(uni_ShadowTexture, pass_TexCoord2 + vec3( uni_ShadowTexelSize, 0.0f, 0.0f)).x + + shadow2D(uni_ShadowTexture, pass_TexCoord2 + vec3(-uni_ShadowTexelSize, 0.0f, 0.0f)).x + + shadow2D(uni_ShadowTexture, pass_TexCoord2 + vec3( 0.0f, uni_ShadowTexelSize, 0.0f)).x + + shadow2D(uni_ShadowTexture, pass_TexCoord2 + vec3( 0.0f, -uni_ShadowTexelSize, 0.0f)).x); shadow = mix(uni_ShadowColor, 1.0f, value); #else From cd140f13841f468ff375cf23c54ae6447d8f2aaa Mon Sep 17 00:00:00 2001 From: DavivaD Date: Sat, 27 Jul 2019 03:36:03 +0200 Subject: [PATCH 04/98] Move mod loading/unloading stuff to a new class + fix some derps --- src/app/pathman.cpp | 40 +++++++++--------- src/ui/screen/screen_setup.cpp | 2 +- src/ui/screen/screen_setup_mods.cpp | 64 ++++++++++++++++++----------- src/ui/screen/screen_setup_mods.h | 4 +- 4 files changed, 65 insertions(+), 45 deletions(-) diff --git a/src/app/pathman.cpp b/src/app/pathman.cpp index 9656d3eb..11776d19 100644 --- a/src/app/pathman.cpp +++ b/src/app/pathman.cpp @@ -72,9 +72,9 @@ void CPathManager::AddModAutoloadDir(const std::string &modAutoloadDirPath) void CPathManager::AddMod(const std::string &modPath) { - std::string::size_type ON; - ON = modPath.find('~'); - if (ON == std::string::npos) + std::string::size_type enabled; + enabled = modPath.find('~'); + if (enabled == std::string::npos) { GetLogger()->Info("Loading mod: '%s'\n", modPath.c_str()); CResourceManager::AddLocation(modPath, true); @@ -87,9 +87,9 @@ void CPathManager::AddMod(const std::string &modPath) void CPathManager::RemoveMod(const std::string &modPath) { - std::string::size_type ON; - ON = modPath.find('~'); - if (ON == std::string::npos) + std::string::size_type enabled; + enabled = modPath.find('~'); + if (enabled == std::string::npos) { GetLogger()->Info("Unloading mod: '%s'\n", modPath.c_str()); CResourceManager::RemoveLocation(modPath); @@ -171,9 +171,9 @@ void CPathManager::InitPaths() GetLogger()->Trace("Searching for mods in '%s'...\n", modAutoloadDir.c_str()); for (const std::string& modPath : FindModsInDir(modAutoloadDir)) { - std::string::size_type ON; - ON = modPath.find('~'); - if (ON == std::string::npos) + std::string::size_type enabled; + enabled = modPath.find('~'); + if (enabled == std::string::npos) { GetLogger()->Info("Autoloading mod: '%s'\n", modPath.c_str()); CResourceManager::AddLocation(modPath); @@ -187,17 +187,17 @@ void CPathManager::InitPaths() for (const std::string& modPath : m_mods) { - std::string::size_type ON; - ON = modPath.find('~'); - if (ON == std::string::npos) - { - GetLogger()->Info("Loading mod: '%s'\n", modPath.c_str()); - CResourceManager::AddLocation(modPath); - } - else - { - GetLogger()->Info("Found excluded mod: '%s'\n", modPath.c_str()); - } + std::string::size_type enabled; + enabled = modPath.find('~'); + if (enabled == std::string::npos) + { + GetLogger()->Info("Loading mod: '%s'\n", modPath.c_str()); + CResourceManager::AddLocation(modPath); + } + else + { + GetLogger()->Info("Found excluded mod: '%s'\n", modPath.c_str()); + } } CResourceManager::SetSaveLocation(m_savePath); diff --git a/src/ui/screen/screen_setup.cpp b/src/ui/screen/screen_setup.cpp index 3dbc0836..66bdac20 100644 --- a/src/ui/screen/screen_setup.cpp +++ b/src/ui/screen/screen_setup.cpp @@ -240,7 +240,7 @@ bool CScreenSetup::EventProcess(const Event &event) return false; case EVENT_INTERFACE_SETUPm: - return false; + assert(false); // should never get here default: break; diff --git a/src/ui/screen/screen_setup_mods.cpp b/src/ui/screen/screen_setup_mods.cpp index 960d7e21..696e6a02 100644 --- a/src/ui/screen/screen_setup_mods.cpp +++ b/src/ui/screen/screen_setup_mods.cpp @@ -1,6 +1,6 @@ /* * This file is part of the Colobot: Gold Edition source code - * Copyright (C) 2001-2018, Daniel Roux, EPSITEC SA & TerranovaTeam + * Copyright (C) 2001-2019, Daniel Roux, EPSITEC SA & TerranovaTeam * http://epsitec.ch; http://colobot.info; http://github.com/colobot * * This program is free software: you can redistribute it and/or modify @@ -127,7 +127,7 @@ bool CScreenSetupMods::EventProcess(const Event &event) CButton* pb; CList* pl; int result; - std::string modName, modPath, modPathRaw, OFF = "~"; + std::string modName, modPath; if (!CScreenSetup::EventProcess(event)) return false; @@ -139,11 +139,8 @@ bool CScreenSetupMods::EventProcess(const Event &event) pl = static_cast(pw->SearchControl(EVENT_INTERFACE_MODS_UNLOADED)); if ( pl == nullptr ) return false; modName = pl->GetItemName(pl->GetSelect()); + LoadMod(modName); - modPathRaw = CResourceManager::GetSaveLocation() + "/" + "mods" + "/"; - modPath = modPathRaw.c_str(); - boost::filesystem::rename(modPath+OFF+modName, modPath+modName); - m_pathManager->AddMod(modPath+modName); m_app->Reload(); m_main->ChangePhase(PHASE_SETUPm); } @@ -152,23 +149,21 @@ bool CScreenSetupMods::EventProcess(const Event &event) pl = static_cast(pw->SearchControl(EVENT_INTERFACE_MODS_LOADED)); if ( pl == nullptr ) return false; modName = pl->GetItemName(pl->GetSelect()); + UnloadMod(modName); - modPathRaw = CResourceManager::GetSaveLocation() + "/" + "mods" + "/"; - modPath = modPathRaw.c_str(); - m_pathManager->RemoveMod(modPath+modName); - boost::filesystem::rename(modPath+modName, modPath+OFF+modName); m_app->Reload(); m_main->ChangePhase(PHASE_SETUPm); } if (event.type == EVENT_INTERFACE_MODS_DIR) { - modPathRaw = CResourceManager::GetSaveLocation() + "/" + "mods"; + modPath = CResourceManager::GetSaveLocation() + "/" + "mods"; #if defined(PLATFORM_WINDOWS) - result = system(("start \""+modPathRaw+"\"").c_str()); + std::replace(modPath.begin(), modPath.end(), '/', '\\'); + result = system(("explorer \""+modPath+"\"").c_str()); #elif defined(PLATFORM_LINUX) - result = system(("xdg-open \""+modPathRaw+"\"").c_str()); + result = system(("xdg-open \""+modPath+"\"").c_str()); #elif defined(PLATFORM_MACOSX) - result = system(("open \""+modPathRaw+"\"").c_str()); + result = system(("open \""+modPath+"\"").c_str()); //TODO: Test on macOS #endif if (result == -1) { @@ -207,11 +202,11 @@ bool CScreenSetupMods::EventProcess(const Event &event) case EVENT_INTERFACE_WORKSHOP: #if defined(PLATFORM_WINDOWS) - result = system("start \"https://colobot.info/forum/forumdisplay.php?fid=60\""); + result = system("rundll32 url.dll,FileProtocolHandler \"https://www.moddb.com/games/colobot-gold-edition\""); #elif defined(PLATFORM_LINUX) - result = system("xdg-open \"https://colobot.info/forum/forumdisplay.php?fid=60\""); + result = system("xdg-open \"https://www.moddb.com/games/colobot-gold-edition\""); #elif defined(PLATFORM_MACOSX) - result = system("open \"https://colobot.info/forum/forumdisplay.php?fid=60\""); + result = system("open \"https://www.moddb.com/games/colobot-gold-edition\""); //TODO: Test on macOS #endif if (result == -1) { @@ -223,6 +218,29 @@ bool CScreenSetupMods::EventProcess(const Event &event) } return false; } + +void CScreenSetupMods::UnloadMod(std::string modName) +{ + std::string modPath, modPathRaw, disabled = "~"; + + modPathRaw = CResourceManager::GetSaveLocation() + "/" + "mods" + "/"; + modPath = modPathRaw.c_str(); + + m_pathManager->RemoveMod(modPath+modName); + boost::filesystem::rename(modPath+modName, modPath+disabled+modName); +} + +void CScreenSetupMods::LoadMod(std::string modName) +{ + std::string modPath, modPathRaw, disabled = "~"; + + modPathRaw = CResourceManager::GetSaveLocation() + "/" + "mods" + "/"; + modPath = modPathRaw.c_str(); + + boost::filesystem::rename(modPath+disabled+modName, modPath+modName); + m_pathManager->AddMod(modPath+modName); +} + void CScreenSetupMods::UpdateUnloadedModList() { CWindow* pw; @@ -243,9 +261,9 @@ void CScreenSetupMods::UpdateUnloadedModList() for(auto const& modNameRaw : modsDir) { modName = modNameRaw; - std::string::size_type ON; - ON = modName.find('~'); - if (ON != std::string::npos) + std::string::size_type enabled; + enabled = modName.find('~'); + if (enabled != std::string::npos) { modName.erase(0,1); pl->SetItemName(i++, modName); @@ -271,9 +289,9 @@ void CScreenSetupMods::UpdateLoadedModList() for(auto const &modName : modsDir) { - std::string::size_type ON; - ON = modName.find('~'); - if (ON == std::string::npos) + std::string::size_type enabled; + enabled = modName.find('~'); + if (enabled == std::string::npos) pl->SetItemName(i++, modName); } pl->ShowSelect(false); // shows the selected columns diff --git a/src/ui/screen/screen_setup_mods.h b/src/ui/screen/screen_setup_mods.h index 0d54502f..e61d75bc 100644 --- a/src/ui/screen/screen_setup_mods.h +++ b/src/ui/screen/screen_setup_mods.h @@ -1,6 +1,6 @@ /* * This file is part of the Colobot: Gold Edition source code - * Copyright (C) 2001-2018, Daniel Roux, EPSITEC SA & TerranovaTeam + * Copyright (C) 2001-2019, Daniel Roux, EPSITEC SA & TerranovaTeam * http://epsitec.ch; http://colobot.info; http://github.com/colobot * * This program is free software: you can redistribute it and/or modify @@ -38,6 +38,8 @@ public: bool EventProcess(const Event &event) override; protected: + void UnloadMod(std::string ModName); + void LoadMod(std::string ModName); void UpdateUnloadedModList(); void UpdateLoadedModList(); From 7d30a827477d1611bea5a2b8f60523e58d6df7b0 Mon Sep 17 00:00:00 2001 From: DavivaD Date: Sat, 27 Jul 2019 16:59:51 +0200 Subject: [PATCH 05/98] Move platform-dependent code to system_*.cpp --- src/common/system/system.cpp | 10 +++++++++ src/common/system/system.h | 6 ++++++ src/common/system/system_linux.cpp | 22 ++++++++++++++++++++ src/common/system/system_linux.h | 3 +++ src/common/system/system_macosx.cpp | 22 ++++++++++++++++++++ src/common/system/system_macosx.h | 3 +++ src/common/system/system_other.cpp | 10 +++++++++ src/common/system/system_other.h | 3 +++ src/common/system/system_windows.cpp | 22 ++++++++++++++++++++ src/common/system/system_windows.h | 3 +++ src/ui/screen/screen_setup_mods.cpp | 31 ++++++---------------------- 11 files changed, 110 insertions(+), 25 deletions(-) diff --git a/src/common/system/system.cpp b/src/common/system/system.cpp index 44064556..3c306ac0 100644 --- a/src/common/system/system.cpp +++ b/src/common/system/system.cpp @@ -192,3 +192,13 @@ std::string CSystemUtils::GetSaveDir() { return "./saves"; } + +void CSystemUtils::OpenPath(std::string path) +{ + assert(false); +} + +void CSystemUtils::OpenWebsite(std::string website) +{ + assert(false); +} diff --git a/src/common/system/system.h b/src/common/system/system.h index aaf54954..2ef0b5cb 100644 --- a/src/common/system/system.h +++ b/src/common/system/system.h @@ -134,6 +134,12 @@ public: //! Returns the save dir location virtual std::string GetSaveDir(); + //! Opens a path with default file browser + virtual void OpenPath(std::string path); + + //! Opens a website with default web browser + virtual void OpenWebsite(std::string website); + //! Sleep for given amount of microseconds virtual void Usleep(int usecs) = 0; diff --git a/src/common/system/system_linux.cpp b/src/common/system/system_linux.cpp index 6578830d..2dda1c00 100644 --- a/src/common/system/system_linux.cpp +++ b/src/common/system/system_linux.cpp @@ -126,6 +126,28 @@ std::string CSystemUtilsLinux::GetSaveDir() #endif } +void CSystemUtilsLinux::OpenPath(std::string path) +{ + int result; + + result = system(("xdg-open \""+path+"\"").c_str()); + if (result == -1) + { + GetLogger()->Error("Failed to open path: %s\n", path.c_str()); + } +} + +void CSystemUtilsLinux::OpenWebsite(std::string website) +{ + int result; + + result = system(("xdg-open \""+website+"\"").c_str()); + if (result == -1) + { + GetLogger()->Error("Failed to open website: %s\n", website.c_str()); + } +} + void CSystemUtilsLinux::Usleep(int usec) { usleep(usec); diff --git a/src/common/system/system_linux.h b/src/common/system/system_linux.h index f1576f31..c41c30d4 100644 --- a/src/common/system/system_linux.h +++ b/src/common/system/system_linux.h @@ -45,6 +45,9 @@ public: std::string GetSaveDir() override; + void OpenPath(std::string path) override; + void OpenWebsite(std::string website) override; + void Usleep(int usec) override; private: diff --git a/src/common/system/system_macosx.cpp b/src/common/system/system_macosx.cpp index 9ef7ce1d..129037aa 100644 --- a/src/common/system/system_macosx.cpp +++ b/src/common/system/system_macosx.cpp @@ -113,6 +113,28 @@ std::string CSystemUtilsMacOSX::GetSaveDir() #endif } +void CSystemUtilsLinux::OpenPath(std::string path) +{ + int result; + + result = system(("open \""+path+"\"").c_str()); // TODO: Test on macOS + if (result == -1) + { + GetLogger()->Error("Failed to open path: %s\n", path.c_str()); + } +} + +void CSystemUtilsLinux::OpenWebsite(std::string website) +{ + int result; + + result = system(("open \""+website+"\"").c_str()); // TODO: Test on macOS + if (result == -1) + { + GetLogger()->Error("Failed to open website: %s\n", website.c_str()); + } +} + void CSystemUtilsMacOSX::Usleep(int usec) { usleep(usec); diff --git a/src/common/system/system_macosx.h b/src/common/system/system_macosx.h index 5b572ec4..dc4d2733 100644 --- a/src/common/system/system_macosx.h +++ b/src/common/system/system_macosx.h @@ -36,6 +36,9 @@ public: std::string GetLangPath() override; std::string GetSaveDir() override; + void OpenPath(std::string path) override; + void OpenWebsite(std::string website) override; + void Usleep(int usec) override; private: diff --git a/src/common/system/system_other.cpp b/src/common/system/system_other.cpp index a3311a74..7d439868 100644 --- a/src/common/system/system_other.cpp +++ b/src/common/system/system_other.cpp @@ -39,6 +39,16 @@ long long int CSystemUtilsOther::TimeStampExactDiff(SystemTimeStamp* before, Sys return (after->sdlTicks - before->sdlTicks) * 1000000ll; } +void CSystemUtilsOther::OpenPath(std::string path) +{ + // TODO +} + +void CSystemUtilsOther::OpenWebsite(std::string website) +{ + // TODO +} + void CSystemUtilsOther::Usleep(int usec) { SDL_Delay(usec / 1000); // close enough diff --git a/src/common/system/system_other.h b/src/common/system/system_other.h index ac80701b..d457b1e6 100644 --- a/src/common/system/system_other.h +++ b/src/common/system/system_other.h @@ -49,6 +49,9 @@ public: void GetCurrentTimeStamp(SystemTimeStamp *stamp) override; long long TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after) override; + void OpenPath(std::string path) override; + void OpenWebsite(std::string website) override; + void Usleep(int usec) override; }; diff --git a/src/common/system/system_windows.cpp b/src/common/system/system_windows.cpp index a20bfcf1..3400817d 100644 --- a/src/common/system/system_windows.cpp +++ b/src/common/system/system_windows.cpp @@ -131,6 +131,28 @@ std::string CSystemUtilsWindows::GetSaveDir() #endif } +void CSystemUtilsWindows::OpenPath(std::string path) +{ + int result; + + result = system(("explorer \""+path+"\"").c_str()); // TODO: Test on macOS + if (result == -1) + { + GetLogger()->Error("Failed to open path: %s\n", path.c_str()); + } +} + +void CSystemUtilsWindows::OpenWebsite(std::string website) +{ + int result; + + result = system(("rundll32 url.dll,FileProtocolHandler \""+website+"\"").c_str()); // TODO: Test on macOS + if (result == -1) + { + GetLogger()->Error("Failed to open website: %s\n", website.c_str()); + } +} + void CSystemUtilsWindows::Usleep(int usec) { LARGE_INTEGER ft; diff --git a/src/common/system/system_windows.h b/src/common/system/system_windows.h index 74f02455..54c8611e 100644 --- a/src/common/system/system_windows.h +++ b/src/common/system/system_windows.h @@ -43,6 +43,9 @@ public: std::string GetSaveDir() override; + void OpenPath(std::string path) override; + void OpenWebsite(std::string website) override; + void Usleep(int usec) override; public: diff --git a/src/ui/screen/screen_setup_mods.cpp b/src/ui/screen/screen_setup_mods.cpp index 696e6a02..d3266e2d 100644 --- a/src/ui/screen/screen_setup_mods.cpp +++ b/src/ui/screen/screen_setup_mods.cpp @@ -22,6 +22,8 @@ #include "app/app.h" #include "app/pathman.h" +#include "common/system/system.h" + #include "common/restext.h" #include "common/config.h" #include "common/logger.h" @@ -126,8 +128,8 @@ bool CScreenSetupMods::EventProcess(const Event &event) CWindow* pw; CButton* pb; CList* pl; - int result; - std::string modName, modPath; + std::string modName, modPath, website = "https://www.moddb.com/games/colobot-gold-edition"; + auto systemUtils = CSystemUtils::Create(); // platform-specific utils if (!CScreenSetup::EventProcess(event)) return false; @@ -157,18 +159,7 @@ bool CScreenSetupMods::EventProcess(const Event &event) if (event.type == EVENT_INTERFACE_MODS_DIR) { modPath = CResourceManager::GetSaveLocation() + "/" + "mods"; - #if defined(PLATFORM_WINDOWS) - std::replace(modPath.begin(), modPath.end(), '/', '\\'); - result = system(("explorer \""+modPath+"\"").c_str()); - #elif defined(PLATFORM_LINUX) - result = system(("xdg-open \""+modPath+"\"").c_str()); - #elif defined(PLATFORM_MACOSX) - result = system(("open \""+modPath+"\"").c_str()); //TODO: Test on macOS - #endif - if (result == -1) - { - GetLogger()->Error("Failed to open Mods directory! Does directory exists?\n"); - } + systemUtils->OpenPath(modPath); } switch (event.type) { @@ -201,17 +192,7 @@ bool CScreenSetupMods::EventProcess(const Event &event) break; case EVENT_INTERFACE_WORKSHOP: - #if defined(PLATFORM_WINDOWS) - result = system("rundll32 url.dll,FileProtocolHandler \"https://www.moddb.com/games/colobot-gold-edition\""); - #elif defined(PLATFORM_LINUX) - result = system("xdg-open \"https://www.moddb.com/games/colobot-gold-edition\""); - #elif defined(PLATFORM_MACOSX) - result = system("open \"https://www.moddb.com/games/colobot-gold-edition\""); //TODO: Test on macOS - #endif - if (result == -1) - { - GetLogger()->Error("Failed to open Workshop page! Is any Web Broswer installed?\n"); - } + systemUtils->OpenWebsite(website); break; default: return true; From 6f3b14202ec33ce697adc67bc5d10ab672833cab Mon Sep 17 00:00:00 2001 From: DavivaD Date: Sat, 27 Jul 2019 17:03:33 +0200 Subject: [PATCH 06/98] Mod Manager i18n --- po/colobot.pot | 21 +++++++++++++++++++++ po/cs.po | 21 +++++++++++++++++++++ po/de.po | 21 +++++++++++++++++++++ po/fr.po | 21 +++++++++++++++++++++ po/pl.po | 21 +++++++++++++++++++++ po/ru.po | 21 +++++++++++++++++++++ 6 files changed, 126 insertions(+) diff --git a/po/colobot.pot b/po/colobot.pot index 5d71af8c..675932b8 100644 --- a/po/colobot.pot +++ b/po/colobot.pot @@ -120,6 +120,12 @@ msgstr "" msgid "2) Then press the key you want to use instead." msgstr "" +msgid "Unloaded Mods:" +msgstr "" + +msgid "Loaded Mods:" +msgstr "" + msgid "Face type:" msgstr "" @@ -334,6 +340,18 @@ msgstr "" msgid "Play\\Start mission!" msgstr "" +msgid "Workshop\\Open Workshop to search Mods" +msgstr "" + +msgid "Open Directory\\Open Mods directory" +msgstr "" + +msgid "Load\\Load Mod" +msgstr "" + +msgid "Unload\\Unload Mod" +msgstr "" + msgid "Device\\Driver and resolution settings" msgstr "" @@ -349,6 +367,9 @@ msgstr "" msgid "Sound\\Music and game sound volume" msgstr "" +msgid "Mods\\Manage installed mods" +msgstr "" + msgid "Unit" msgstr "" diff --git a/po/cs.po b/po/cs.po index 555df720..cee89994 100644 --- a/po/cs.po +++ b/po/cs.po @@ -817,12 +817,18 @@ msgstr "Seznam uložených misí" msgid "Load a saved mission" msgstr "Nahrát uloženou misi" +msgid "Load\\Load Mod" +msgstr "" + msgid "Load\\Load a saved mission" msgstr "Nahrát\\Nahrát uloženou misi" msgid "Load\\Loads the selected mission" msgstr "Nahrát\\Nahraje vybranou misi" +msgid "Loaded Mods:" +msgstr "" + msgid "Loading basic level settings" msgstr "Načítám základní nastavení mapy" @@ -877,6 +883,9 @@ msgstr "Mise na této planetě:" msgid "Missions\\Select mission" msgstr "Mise\\Vyberte misi" +msgid "Mods\\Manage installed mods" +msgstr "" + msgid "Mouse inversion X\\Inversion of the scrolling direction on the X axis" msgstr "Vodorovné převrácení posunu\\Při vodorovném posunu kamery myší pousouvat opačným směrem" @@ -1039,6 +1048,9 @@ msgstr "Otevřít" msgid "Open (Ctrl+O)" msgstr "Otevřít (Ctrl+O)" +msgid "Open Directory\\Open Mods directory" +msgstr "" + msgid "Opening brace missing" msgstr "Chybí levá složená závorka" @@ -1640,6 +1652,12 @@ msgstr "Neznámá zástupná sekvence" msgid "Unknown function" msgstr "Neznámá funkce" +msgid "Unload\\Unload Mod" +msgstr "" + +msgid "Unloaded Mods:" +msgstr "" + msgid "Up (\\key gup;)" msgstr "Vzhůru (\\key gup;)" @@ -1706,6 +1724,9 @@ msgstr "Létající detektor" msgid "Withdraw shield (\\key action;)" msgstr "Vypnout štít (\\key action;)" +msgid "Workshop\\Open Workshop to search Mods" +msgstr "" + msgid "Worm" msgstr "Červ" diff --git a/po/de.po b/po/de.po index 553ead83..ca53d3cb 100644 --- a/po/de.po +++ b/po/de.po @@ -819,12 +819,18 @@ msgstr "Liste der gespeicherten Missionen" msgid "Load a saved mission" msgstr "Gespeicherte Mission laden" +msgid "Load\\Load Mod" +msgstr "" + msgid "Load\\Load a saved mission" msgstr "Laden\\Eine gespeicherte Mission öffnen" msgid "Load\\Loads the selected mission" msgstr "Laden\\Öffnet eine gespeicherte Mission" +msgid "Loaded Mods:" +msgstr "" + msgid "Loading basic level settings" msgstr "Lade Level-Grundeinstellungen" @@ -893,6 +899,9 @@ msgstr "Liste der Missionen des Planeten:" msgid "Missions\\Select mission" msgstr "Missionen\\Aufbruch ins Weltall" +msgid "Mods\\Manage installed mods" +msgstr "" + msgid "Mouse inversion X\\Inversion of the scrolling direction on the X axis" msgstr "Umkehr X\\Umkehr der Kameradrehung X-Achse" @@ -1055,6 +1064,9 @@ msgstr "Öffnen" msgid "Open (Ctrl+O)" msgstr "Öffnen (Ctrl+O)" +msgid "Open Directory\\Open Mods directory" +msgstr "" + msgid "Opening brace missing" msgstr "Es fehlt eine offene geschweifte Klammer\"{\"" @@ -1657,6 +1669,12 @@ msgstr "" msgid "Unknown function" msgstr "Unbekannte Funktion" +msgid "Unload\\Unload Mod" +msgstr "" + +msgid "Unloaded Mods:" +msgstr "" + msgid "Up (\\key gup;)" msgstr "Steigt (\\key gup;)" @@ -1723,6 +1741,9 @@ msgstr "Schnüffler" msgid "Withdraw shield (\\key action;)" msgstr "Schutzschild einholen (\\key action;)" +msgid "Workshop\\Open Workshop to search Mods" +msgstr "" + msgid "Worm" msgstr "Wurm" diff --git a/po/fr.po b/po/fr.po index ce3f5fdf..76afb80c 100644 --- a/po/fr.po +++ b/po/fr.po @@ -821,12 +821,18 @@ msgstr "Liste des missions enregistrées" msgid "Load a saved mission" msgstr "Chargement d'une mission enregistrée" +msgid "Load\\Load Mod" +msgstr "" + msgid "Load\\Load a saved mission" msgstr "Charger\\Charger une mission enregistrée" msgid "Load\\Loads the selected mission" msgstr "Charger\\Charger la mission sélectionnée" +msgid "Loaded Mods:" +msgstr "" + msgid "Loading basic level settings" msgstr "Chargement des configurations de base du niveau" @@ -895,6 +901,9 @@ msgstr "Liste des missions du chapitre :" msgid "Missions\\Select mission" msgstr "Missions\\La grande aventure" +msgid "Mods\\Manage installed mods" +msgstr "" + msgid "Mouse inversion X\\Inversion of the scrolling direction on the X axis" msgstr "Inversion souris X\\Inversion de la rotation lorsque la souris touche un bord" @@ -1057,6 +1066,9 @@ msgstr "Ouvrir" msgid "Open (Ctrl+O)" msgstr "Ouvrir (Ctrl+O)" +msgid "Open Directory\\Open Mods directory" +msgstr "" + msgid "Opening brace missing" msgstr "Début d'un bloc attendu" @@ -1660,6 +1672,12 @@ msgstr "" msgid "Unknown function" msgstr "Routine inconnue" +msgid "Unload\\Unload Mod" +msgstr "" + +msgid "Unloaded Mods:" +msgstr "" + msgid "Up (\\key gup;)" msgstr "Monte (\\key gup;)" @@ -1726,6 +1744,9 @@ msgstr "Robot renifleur volant" msgid "Withdraw shield (\\key action;)" msgstr "Refermer le bouclier (\\key action;)" +msgid "Workshop\\Open Workshop to search Mods" +msgstr "" + msgid "Worm" msgstr "Ver" diff --git a/po/pl.po b/po/pl.po index f9f76de8..4dd75cc4 100644 --- a/po/pl.po +++ b/po/pl.po @@ -816,12 +816,18 @@ msgstr "Lista zapisanych misji" msgid "Load a saved mission" msgstr "Wczytaj zapisaną misję" +msgid "Load\\Load Mod" +msgstr "" + msgid "Load\\Load a saved mission" msgstr "Wczytaj\\Wczytuje zapisaną misję" msgid "Load\\Loads the selected mission" msgstr "Wczytaj\\Wczytuje zaznaczoną misję" +msgid "Loaded Mods:" +msgstr "" + msgid "Loading basic level settings" msgstr "Wczytywanie ustawień poziomu" @@ -876,6 +882,9 @@ msgstr "Misje na tej planecie:" msgid "Missions\\Select mission" msgstr "Misje\\Wybierz misję" +msgid "Mods\\Manage installed mods" +msgstr "" + msgid "Mouse inversion X\\Inversion of the scrolling direction on the X axis" msgstr "Odwrócenie myszy X\\Odwrócenie kierunków przewijania w poziomie" @@ -1038,6 +1047,9 @@ msgstr "Otwórz" msgid "Open (Ctrl+O)" msgstr "Otwórz (Ctrl+O)" +msgid "Open Directory\\Open Mods directory" +msgstr "" + msgid "Opening brace missing" msgstr "Brak klamry otwierającej" @@ -1639,6 +1651,12 @@ msgstr "" msgid "Unknown function" msgstr "Funkcja nieznana" +msgid "Unload\\Unload Mod" +msgstr "" + +msgid "Unloaded Mods:" +msgstr "" + msgid "Up (\\key gup;)" msgstr "Góra (\\key gup;)" @@ -1705,6 +1723,9 @@ msgstr "Szperacz latający" msgid "Withdraw shield (\\key action;)" msgstr "Wyłącz osłonę (\\key action;)" +msgid "Workshop\\Open Workshop to search Mods" +msgstr "" + msgid "Worm" msgstr "Robal" diff --git a/po/ru.po b/po/ru.po index 0763e742..21266749 100644 --- a/po/ru.po +++ b/po/ru.po @@ -825,12 +825,18 @@ msgstr "Список сохраненных миссий" msgid "Load a saved mission" msgstr "Загрузить" +msgid "Load\\Load Mod" +msgstr "" + msgid "Load\\Load a saved mission" msgstr "Загрузить\\Загрузить сохраненную миссию" msgid "Load\\Loads the selected mission" msgstr "Загрузить\\Загрузить выбранную миссию" +msgid "Loaded Mods:" +msgstr "" + msgid "Loading basic level settings" msgstr "Загрузка основных настроек уровня" @@ -899,6 +905,9 @@ msgstr "Миссии на этой планете:" msgid "Missions\\Select mission" msgstr "Миссии\\Выбор миссии" +msgid "Mods\\Manage installed mods" +msgstr "" + msgid "Mouse inversion X\\Inversion of the scrolling direction on the X axis" msgstr "Инверсия мыши по оси X\\Инверсия прокрутки по оси Х" @@ -1063,6 +1072,9 @@ msgstr "Открыть" msgid "Open (Ctrl+O)" msgstr "Открыть (Ctrl+O)" +msgid "Open Directory\\Open Mods directory" +msgstr "" + msgid "Opening brace missing" msgstr "Открывающая скобка отсутствует" @@ -1670,6 +1682,12 @@ msgstr "" msgid "Unknown function" msgstr "Неизвестная функция" +msgid "Unload\\Unload Mod" +msgstr "" + +msgid "Unloaded Mods:" +msgstr "" + msgid "Up (\\key gup;)" msgstr "Вверх (\\key gup;)" @@ -1736,6 +1754,9 @@ msgstr "Летающий искатель" msgid "Withdraw shield (\\key action;)" msgstr "Снять щит (\\key action;)" +msgid "Workshop\\Open Workshop to search Mods" +msgstr "" + msgid "Worm" msgstr "Червь" From 50c3c45ef8d536c594cbe5fa65b615ea2397de47 Mon Sep 17 00:00:00 2001 From: DavivaD Date: Sat, 27 Jul 2019 17:58:12 +0200 Subject: [PATCH 07/98] Show only local mods on the list --- src/ui/screen/screen_setup_mods.cpp | 39 ++++++++++++++++++----------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/src/ui/screen/screen_setup_mods.cpp b/src/ui/screen/screen_setup_mods.cpp index d3266e2d..3779ee32 100644 --- a/src/ui/screen/screen_setup_mods.cpp +++ b/src/ui/screen/screen_setup_mods.cpp @@ -41,6 +41,9 @@ #include #include +#include + +using namespace boost::filesystem; namespace Ui { @@ -224,10 +227,11 @@ void CScreenSetupMods::LoadMod(std::string modName) void CScreenSetupMods::UpdateUnloadedModList() { - CWindow* pw; - CList* pl; - int i = 0; - std::string modName; + CWindow* pw; + CList* pl; + int i = 0; + std::string modPath, modPathRaw; + directory_iterator end_itr; pw = static_cast(m_interface->SearchControl(EVENT_WINDOW5)); if ( pw == nullptr ) return; @@ -236,12 +240,13 @@ void CScreenSetupMods::UpdateUnloadedModList() if ( pl == nullptr ) return; pl->Flush(); - auto modsDir = CResourceManager::ListDirectories("mods/"); - std::sort(modsDir.begin(), modsDir.end()); + modPathRaw = CResourceManager::GetSaveLocation() + "/" + "mods" + "/"; + modPath = modPathRaw.c_str(); - for(auto const& modNameRaw : modsDir) + for (directory_iterator itr(modPath); itr != end_itr; ++itr) { - modName = modNameRaw; + std::string modName = itr->path().string(); + boost::erase_all(modName, modPath); std::string::size_type enabled; enabled = modName.find('~'); if (enabled != std::string::npos) @@ -250,13 +255,16 @@ void CScreenSetupMods::UpdateUnloadedModList() pl->SetItemName(i++, modName); } } + pl->ShowSelect(false); // shows the selected columns } void CScreenSetupMods::UpdateLoadedModList() { - CWindow* pw; - CList* pl; - int i = 0; + CWindow* pw; + CList* pl; + int i = 0; + std::string modPath, modPathRaw; + directory_iterator end_itr; pw = static_cast(m_interface->SearchControl(EVENT_WINDOW5)); if ( pw == nullptr ) return; @@ -265,16 +273,19 @@ void CScreenSetupMods::UpdateLoadedModList() if ( pl == nullptr ) return; pl->Flush(); - auto modsDir = CResourceManager::ListDirectories("mods/"); - std::sort(modsDir.begin(), modsDir.end()); + modPathRaw = CResourceManager::GetSaveLocation() + "/" + "mods" + "/"; + modPath = modPathRaw.c_str(); - for(auto const &modName : modsDir) + for (directory_iterator itr(modPath); itr != end_itr; ++itr) { + std::string modName = itr->path().string(); + boost::erase_all(modName, modPath); std::string::size_type enabled; enabled = modName.find('~'); if (enabled == std::string::npos) pl->SetItemName(i++, modName); } + pl->ShowSelect(false); // shows the selected columns } } // namespace Ui From 0d3062411935df881fdcfd7055f780946e8b6552 Mon Sep 17 00:00:00 2001 From: Martin Doucha Date: Tue, 2 Jul 2019 21:17:40 +0200 Subject: [PATCH 08/98] Fix OpenGL 2.1 specular lighting --- src/graphics/opengl/gl21device.cpp | 9 +++++++++ src/graphics/opengl/glutil.h | 2 ++ src/graphics/opengl/shaders/gl21/fs_normal.glsl | 8 +++++--- src/graphics/opengl/shaders/gl21/vs_normal.glsl | 3 +++ 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/graphics/opengl/gl21device.cpp b/src/graphics/opengl/gl21device.cpp index 41660578..970a8788 100644 --- a/src/graphics/opengl/gl21device.cpp +++ b/src/graphics/opengl/gl21device.cpp @@ -388,6 +388,7 @@ bool CGL21Device::Create() uni.modelMatrix = glGetUniformLocation(m_normalProgram, "uni_ModelMatrix"); uni.normalMatrix = glGetUniformLocation(m_normalProgram, "uni_NormalMatrix"); uni.shadowMatrix = glGetUniformLocation(m_normalProgram, "uni_ShadowMatrix"); + uni.cameraPosition = glGetUniformLocation(m_normalProgram, "uni_CameraPosition"); uni.primaryTexture = glGetUniformLocation(m_normalProgram, "uni_PrimaryTexture"); uni.secondaryTexture = glGetUniformLocation(m_normalProgram, "uni_SecondaryTexture"); @@ -441,6 +442,7 @@ bool CGL21Device::Create() glUniformMatrix4fv(uni.modelMatrix, 1, GL_FALSE, matrix.Array()); glUniformMatrix4fv(uni.normalMatrix, 1, GL_FALSE, matrix.Array()); glUniformMatrix4fv(uni.shadowMatrix, 1, GL_FALSE, matrix.Array()); + glUniform3f(uni.cameraPosition, 0.0f, 0.0f, 0.0f); glUniform1i(uni.primaryTexture, 0); glUniform1i(uni.secondaryTexture, 1); @@ -653,6 +655,7 @@ void CGL21Device::SetTransform(TransformType type, const Math::Matrix &matrix) else if (type == TRANSFORM_VIEW) { Math::Matrix scale; + Math::Vector cameraPosition; scale.Set(3, 3, -1.0f); m_viewMat = Math::MultiplyMatrices(scale, matrix); @@ -660,6 +663,12 @@ void CGL21Device::SetTransform(TransformType type, const Math::Matrix &matrix) m_combinedMatrix = Math::MultiplyMatrices(m_projectionMat, m_modelviewMat); glUniformMatrix4fv(m_uniforms[m_mode].viewMatrix, 1, GL_FALSE, m_viewMat.Array()); + + if (m_uniforms[m_mode].cameraPosition >= 0) { + cameraPosition.LoadZero(); + cameraPosition = MatrixVectorMultiply(m_viewMat.Inverse(), cameraPosition); + glUniform3fv(m_uniforms[m_mode].cameraPosition, 1, cameraPosition.Array()); + } } else if (type == TRANSFORM_PROJECTION) { diff --git a/src/graphics/opengl/glutil.h b/src/graphics/opengl/glutil.h index 977bc9c3..b47d7300 100644 --- a/src/graphics/opengl/glutil.h +++ b/src/graphics/opengl/glutil.h @@ -167,6 +167,8 @@ struct UniformLocations GLint shadowMatrix = -1; //! Normal matrix GLint normalMatrix = -1; + //! Camera position + GLint cameraPosition = -1; //! Primary texture sampler GLint primaryTexture = -1; diff --git a/src/graphics/opengl/shaders/gl21/fs_normal.glsl b/src/graphics/opengl/shaders/gl21/fs_normal.glsl index d21bc9cf..3cefb8e6 100644 --- a/src/graphics/opengl/shaders/gl21/fs_normal.glsl +++ b/src/graphics/opengl/shaders/gl21/fs_normal.glsl @@ -56,6 +56,7 @@ uniform Material uni_Material; uniform int uni_LightCount; uniform LightParams uni_Light[4]; +varying vec3 pass_CameraDirection; varying float pass_Distance; varying vec4 pass_Color; varying vec3 pass_Normal; @@ -76,16 +77,17 @@ void main() vec4 specular = vec4(0.0f); vec3 normal = normalize(pass_Normal); + vec3 camera = normalize(pass_CameraDirection); for (int i = 0; i < uni_LightCount; i++) { LightParams light = uni_Light[i]; - vec3 lightDirection = light.Position.xyz; - vec3 reflectDirection = -reflect(lightDirection, normal); + vec3 lightDirection = normalize(light.Position.xyz); + vec3 reflectAxis = normalize(lightDirection + camera); float diffuseComponent = clamp(dot(normal, lightDirection), 0.0f, 1.0f); - float specularComponent = clamp(pow(dot(normal, lightDirection + reflectDirection), 10.0f), 0.0f, 1.0f); + float specularComponent = pow(clamp(dot(normal, reflectAxis), 0.0f, 1.0f), 10.0f); ambient += light.Ambient; diffuse += diffuseComponent * light.Diffuse; diff --git a/src/graphics/opengl/shaders/gl21/vs_normal.glsl b/src/graphics/opengl/shaders/gl21/vs_normal.glsl index 9195cd20..41141c4b 100644 --- a/src/graphics/opengl/shaders/gl21/vs_normal.glsl +++ b/src/graphics/opengl/shaders/gl21/vs_normal.glsl @@ -24,7 +24,9 @@ uniform mat4 uni_ViewMatrix; uniform mat4 uni_ModelMatrix; uniform mat4 uni_ShadowMatrix; uniform mat4 uni_NormalMatrix; +uniform vec3 uni_CameraPosition; +varying vec3 pass_CameraDirection; varying float pass_Distance; varying vec4 pass_Color; varying vec3 pass_Normal; @@ -40,6 +42,7 @@ void main() gl_Position = uni_ProjectionMatrix * eyeSpace; + pass_CameraDirection = uni_CameraPosition - position.xyz; pass_Color = gl_Color; pass_Normal = normalize((uni_NormalMatrix * vec4(gl_Normal, 0.0f)).xyz); pass_Distance = abs(eyeSpace.z / eyeSpace.w); From 69aba7c352dc4d199309b9d4ee60403943d2a0e9 Mon Sep 17 00:00:00 2001 From: Martin Doucha Date: Sun, 29 Dec 2019 14:44:38 +0100 Subject: [PATCH 09/98] Fix OpenGL 3.3 specular lighting --- src/graphics/opengl/gl33device.cpp | 9 +++++++++ src/graphics/opengl/shaders/gl33/fs_normal.glsl | 9 +++++---- src/graphics/opengl/shaders/gl33/vs_normal.glsl | 3 +++ 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/graphics/opengl/gl33device.cpp b/src/graphics/opengl/gl33device.cpp index 0180f247..6d3a91eb 100644 --- a/src/graphics/opengl/gl33device.cpp +++ b/src/graphics/opengl/gl33device.cpp @@ -363,6 +363,7 @@ bool CGL33Device::Create() uni.modelMatrix = glGetUniformLocation(m_normalProgram, "uni_ModelMatrix"); uni.normalMatrix = glGetUniformLocation(m_normalProgram, "uni_NormalMatrix"); uni.shadowMatrix = glGetUniformLocation(m_normalProgram, "uni_ShadowMatrix"); + uni.cameraPosition = glGetUniformLocation(m_normalProgram, "uni_CameraPosition"); uni.primaryTexture = glGetUniformLocation(m_normalProgram, "uni_PrimaryTexture"); uni.secondaryTexture = glGetUniformLocation(m_normalProgram, "uni_SecondaryTexture"); @@ -420,6 +421,7 @@ bool CGL33Device::Create() glUniformMatrix4fv(uni.modelMatrix, 1, GL_FALSE, matrix.Array()); glUniformMatrix4fv(uni.normalMatrix, 1, GL_FALSE, matrix.Array()); glUniformMatrix4fv(uni.shadowMatrix, 1, GL_FALSE, matrix.Array()); + glUniform3f(uni.cameraPosition, 0.0f, 0.0f, 0.0f); glUniform1i(uni.primaryTexture, 0); glUniform1i(uni.secondaryTexture, 1); @@ -660,6 +662,7 @@ void CGL33Device::SetTransform(TransformType type, const Math::Matrix &matrix) else if (type == TRANSFORM_VIEW) { Math::Matrix scale; + Math::Vector cameraPosition; scale.Set(3, 3, -1.0f); m_viewMat = Math::MultiplyMatrices(scale, matrix); @@ -667,6 +670,12 @@ void CGL33Device::SetTransform(TransformType type, const Math::Matrix &matrix) m_combinedMatrixOutdated = true; glUniformMatrix4fv(m_uni->viewMatrix, 1, GL_FALSE, m_viewMat.Array()); + + if (m_uni->cameraPosition >= 0) { + cameraPosition.LoadZero(); + cameraPosition = MatrixVectorMultiply(m_viewMat.Inverse(), cameraPosition); + glUniform3fv(m_uni->cameraPosition, 1, cameraPosition.Array()); + } } else if (type == TRANSFORM_PROJECTION) { diff --git a/src/graphics/opengl/shaders/gl33/fs_normal.glsl b/src/graphics/opengl/shaders/gl33/fs_normal.glsl index e6fd1e07..7b498723 100644 --- a/src/graphics/opengl/shaders/gl33/fs_normal.glsl +++ b/src/graphics/opengl/shaders/gl33/fs_normal.glsl @@ -63,6 +63,7 @@ in VertexData vec4 ShadowCoord; vec4 LightColor; float Distance; + vec3 CameraDirection; } data; out vec4 out_FragColor; @@ -78,17 +79,17 @@ void main() vec4 specular = vec4(0.0f); vec3 normal = normalize(data.Normal); + vec3 camera = normalize(data.CameraDirection); for (int i = 0; i < uni_LightCount; i++) { - vec3 lightDirection = uni_Light[i].Position.xyz; - - vec3 reflectDirection = -reflect(lightDirection, normal); + vec3 lightDirection = normalize(uni_Light[i].Position.xyz); + vec3 reflectAxis = normalize(lightDirection + camera); ambient += uni_Light[i].Ambient; diffuse += clamp(dot(normal, lightDirection), 0.0f, 1.0f) * uni_Light[i].Diffuse; - specular += clamp(pow(dot(normal, lightDirection + reflectDirection), 10.0f), 0.0f, 1.0f) + specular += pow(clamp(dot(normal, reflectAxis), 0.0f, 1.0f), 10.0f) * uni_Light[i].Specular; } diff --git a/src/graphics/opengl/shaders/gl33/vs_normal.glsl b/src/graphics/opengl/shaders/gl33/vs_normal.glsl index aeed3c60..216682f7 100644 --- a/src/graphics/opengl/shaders/gl33/vs_normal.glsl +++ b/src/graphics/opengl/shaders/gl33/vs_normal.glsl @@ -25,6 +25,7 @@ uniform mat4 uni_ViewMatrix; uniform mat4 uni_ModelMatrix; uniform mat4 uni_ShadowMatrix; uniform mat4 uni_NormalMatrix; +uniform vec3 uni_CameraPosition; layout(location = 0) in vec4 in_VertexCoord; layout(location = 1) in vec3 in_Normal; @@ -41,6 +42,7 @@ out VertexData vec4 ShadowCoord; vec4 LightColor; float Distance; + vec3 CameraDirection; } data; void main() @@ -56,4 +58,5 @@ void main() data.Normal = normalize((uni_NormalMatrix * vec4(in_Normal, 0.0f)).xyz); data.ShadowCoord = vec4(shadowCoord.xyz / shadowCoord.w, 1.0f); data.Distance = abs(eyeSpace.z); + data.CameraDirection = uni_CameraPosition - position.xyz; } From c50b36118efa8f936f36763c64a03445222983e1 Mon Sep 17 00:00:00 2001 From: Fiftytwo Date: Tue, 7 Jul 2020 09:40:47 +0200 Subject: [PATCH 10/98] Revert "Make Recycler Recycle small Building Ruins." --- src/object/task/taskrecover.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/object/task/taskrecover.cpp b/src/object/task/taskrecover.cpp index 872632ed..e3fa9e41 100644 --- a/src/object/task/taskrecover.cpp +++ b/src/object/task/taskrecover.cpp @@ -376,5 +376,5 @@ bool CTaskRecover::Abort() CObject* CTaskRecover::SearchRuin() { - return CObjectManager::GetInstancePointer()->FindNearest(nullptr, m_recoverPos, {OBJECT_RUINmobilew1, OBJECT_RUINmobilew2, OBJECT_RUINmobilet1, OBJECT_RUINmobilet2, OBJECT_RUINmobiler1, OBJECT_RUINmobiler2, OBJECT_RUINdoor, OBJECT_RUINsupport, OBJECT_RUINradar}, 40.0f/g_unit); + return CObjectManager::GetInstancePointer()->FindNearest(nullptr, m_recoverPos, {OBJECT_RUINmobilew1, OBJECT_RUINmobilew2, OBJECT_RUINmobilet1, OBJECT_RUINmobilet2, OBJECT_RUINmobiler1, OBJECT_RUINmobiler2}, 40.0f/g_unit); } From 6a23e97533de23d4574b9e5e742b590dafdbf395 Mon Sep 17 00:00:00 2001 From: Fiftytwo Date: Wed, 8 Jul 2020 14:17:08 +0200 Subject: [PATCH 11/98] Fix collisions of animated plants --- src/object/old_object.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/object/old_object.cpp b/src/object/old_object.cpp index c11247d2..0e8fb670 100644 --- a/src/object/old_object.cpp +++ b/src/object/old_object.cpp @@ -1274,7 +1274,7 @@ int COldObject::SearchDescendant(int parent, int n) void COldObject::TransformCrashSphere(Math::Sphere& crashSphere) { - crashSphere.radius *= GetScaleX(); + if(!Implements(ObjectInterfaceType::Jostleable)) crashSphere.radius *= GetScaleX(); // Returns to the sphere collisions, // which ignores the tilt of the vehicle. From 963cd1b347331c501a2bbb8a1caef7512fbab905 Mon Sep 17 00:00:00 2001 From: MrSimbax Date: Fri, 10 Jul 2020 10:53:38 +0200 Subject: [PATCH 12/98] Fix sed cmd not working with MSBuild Fixes the `'\1' is not recognized as an internal or external command` error when trying to run the target `update-pot` with MSBuild. The `|` characters probably messed with cmd.exe or PowerShell syntax rules so they were replaced with slashes `/`. Also, at least some implementations of sed for Windows would produce CRLF line endings instead of LF line endings. The issue is fixed by adding the flag `-b`. --- po/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/po/CMakeLists.txt b/po/CMakeLists.txt index 6a5d7073..28229f32 100644 --- a/po/CMakeLists.txt +++ b/po/CMakeLists.txt @@ -12,7 +12,7 @@ add_custom_command(OUTPUT ${_potFile} COMMAND ${XGETTEXT_CMD} ${colobot_SOURCE_DIR}/src/app/app.cpp --output=${_potFile} --no-wrap COMMAND ${XGETTEXT_CMD} ${colobot_SOURCE_DIR}/src/common/restext.cpp --output=${_potFile} --no-wrap --join-existing --no-location --keyword=TR COMMAND ${XGETTEXT_CMD} ${colobot_SOURCE_DIR}/src/script/script.cpp --output=${_potFile} --no-wrap --join-existing --no-location - COMMAND sed -i -e "s|^\\(\"POT-Creation-Date:\\).*$|\\1 DATE\\\\n\"|" ${_potFile} + COMMAND sed -bi -e "s/^\\(\"POT-Creation-Date:\\).*$/\\1 DATE\\\\n\"/" ${_potFile} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMENT "Extract translatable messages to ${_potFile}" From bf1982f4e4a4d511563df07d0601b91aedbe4c11 Mon Sep 17 00:00:00 2001 From: MrSimbax Date: Fri, 10 Jul 2020 11:01:47 +0200 Subject: [PATCH 13/98] Change `make update-pot` comment to cmake command `make update-pot` only works if a generator producing Makefiles was used with `cmake`. The `cmake` command to build a specific target will work for any generator. --- src/common/restext.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/restext.cpp b/src/common/restext.cpp index 40b34565..cd05d59f 100644 --- a/src/common/restext.cpp +++ b/src/common/restext.cpp @@ -48,8 +48,8 @@ const char* stringsCbot[CBot::CBotErrMAX] = { nullptr }; */ #define TR(x) x -/* Please run `make update-pot` after changing this file - * in order to update translation files. Thank you. +/* Please run `cmake --build --target update-pot` + * after changing this file in order to update translation files. Thank you. */ void InitializeRestext() From 7d7a29117edd87ec62b0a8b5ea1200087ca9e9e9 Mon Sep 17 00:00:00 2001 From: Krzysztof Dermont Date: Tue, 7 Jul 2020 00:06:29 +0200 Subject: [PATCH 14/98] Save audio settings when option changes Mute/unmute option when game windowis in background relies on settings being updates. This happens when users leaves Options screen. This commit adds saving audio settings on each change. This is a fix for #1315 --- src/common/settings.cpp | 17 +++++++++++++---- src/common/settings.h | 1 + src/level/robotmain.cpp | 4 ++-- src/ui/screen/screen_setup_sound.cpp | 4 ++++ 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/common/settings.cpp b/src/common/settings.cpp index 021fa37c..7c72030e 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -72,7 +72,6 @@ void CSettings::SaveSettings() CRobotMain* main = CRobotMain::GetInstancePointer(); Gfx::CEngine* engine = Gfx::CEngine::GetInstancePointer(); Gfx::CCamera* camera = main->GetCamera(); - CSoundInterface* sound = app->GetSound(); GetConfigFile().SetBoolProperty("Setup", "Tooltips", m_tooltips); GetConfigFile().SetBoolProperty("Setup", "InterfaceGlint", m_interfaceGlint); @@ -80,7 +79,6 @@ void CSettings::SaveSettings() GetConfigFile().SetBoolProperty("Setup", "Soluce4", m_soluce4); GetConfigFile().SetBoolProperty("Setup", "Movies", m_movies); GetConfigFile().SetBoolProperty("Setup", "FocusLostPause", m_focusLostPause); - GetConfigFile().SetBoolProperty("Setup", "FocusLostMute", m_focusLostMute); GetConfigFile().SetBoolProperty("Setup", "OldCameraScroll", camera->GetOldCameraScroll()); GetConfigFile().SetBoolProperty("Setup", "CameraInvertX", camera->GetCameraInvertX()); GetConfigFile().SetBoolProperty("Setup", "CameraInvertY", camera->GetCameraInvertY()); @@ -95,8 +93,6 @@ void CSettings::SaveSettings() GetConfigFile().SetIntProperty("Setup", "JoystickIndex", app->GetJoystickEnabled() ? app->GetJoystick().index : -1); GetConfigFile().SetFloatProperty("Setup", "ParticleDensity", engine->GetParticleDensity()); GetConfigFile().SetFloatProperty("Setup", "ClippingDistance", engine->GetClippingDistance()); - GetConfigFile().SetIntProperty("Setup", "AudioVolume", sound->GetAudioVolume()); - GetConfigFile().SetIntProperty("Setup", "MusicVolume", sound->GetMusicVolume()); GetConfigFile().SetBoolProperty("Setup", "EditIndentMode", engine->GetEditIndentMode()); GetConfigFile().SetIntProperty("Setup", "EditIndentValue", engine->GetEditIndentValue()); GetConfigFile().SetBoolProperty("Setup", "PauseBlur", engine->GetPauseBlurEnabled()); @@ -112,6 +108,9 @@ void CSettings::SaveSettings() GetConfigFile().SetIntProperty("Setup", "ShadowMappingResolution", engine->GetShadowMappingOffscreen() ? engine->GetShadowMappingOffscreenResolution() : 0); + // Save Audio settings + SaveAudioSettings(); + // Experimental settings GetConfigFile().SetBoolProperty("Experimental", "TerrainShadows", engine->GetTerrainShadows()); GetConfigFile().SetIntProperty("Setup", "VSync", engine->GetVSync()); @@ -140,6 +139,16 @@ void CSettings::SaveSettings() GetConfigFile().Save(); } +void CSettings::SaveAudioSettings() +{ + CApplication* app = CApplication::GetInstancePointer(); + CSoundInterface* sound = app->GetSound(); + + GetConfigFile().SetIntProperty("Setup", "AudioVolume", sound->GetAudioVolume()); + GetConfigFile().SetIntProperty("Setup", "MusicVolume", sound->GetMusicVolume()); + GetConfigFile().SetBoolProperty("Setup", "FocusLostMute", m_focusLostMute); +} + void CSettings::LoadSettings() { CApplication* app = CApplication::GetInstancePointer(); diff --git a/src/common/settings.h b/src/common/settings.h index 6ebf6e22..010fd036 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -37,6 +37,7 @@ public: void SaveSettings(); void LoadSettings(); + void SaveAudioSettings(); void SetTooltips(bool tooltips); bool GetTooltips(); diff --git a/src/level/robotmain.cpp b/src/level/robotmain.cpp index 6bf29755..1a51c7e1 100644 --- a/src/level/robotmain.cpp +++ b/src/level/robotmain.cpp @@ -742,7 +742,7 @@ bool CRobotMain::ProcessEvent(Event &event) } else { - m_sound->SetMusicVolume(100); + m_sound->SetMusicVolume(MAXVOLUME*3/4); } // Set audio volume if (GetConfigFile().GetIntProperty("Setup", "AudioVolume", volume)) @@ -751,7 +751,7 @@ bool CRobotMain::ProcessEvent(Event &event) } else { - m_sound->SetAudioVolume(100); + m_sound->SetAudioVolume(MAXVOLUME); } } diff --git a/src/ui/screen/screen_setup_sound.cpp b/src/ui/screen/screen_setup_sound.cpp index a963aac4..4f72b7bf 100644 --- a/src/ui/screen/screen_setup_sound.cpp +++ b/src/ui/screen/screen_setup_sound.cpp @@ -173,6 +173,8 @@ void CScreenSetupSound::UpdateSetupButtons() { pc->SetState(STATE_CHECK, m_settings->GetFocusLostMute()); } + + m_settings->SaveAudioSettings(); } // Updates the engine function of the buttons after the setup phase. @@ -199,6 +201,8 @@ void CScreenSetupSound::ChangeSetupButtons() value = ps->GetVisibleValue(); m_sound->SetMusicVolume(static_cast(value)); } + + m_settings->SaveAudioSettings(); } } // namespace Ui From a2aeef015523632fade448d4a2b7e536701eeae6 Mon Sep 17 00:00:00 2001 From: immibis Date: Sun, 6 Aug 2017 22:03:28 +1200 Subject: [PATCH 15/98] When game speed is 2 or higher, run multiple ticks. --- src/app/app.cpp | 47 +++++++++++++++++++--------- src/app/app.h | 2 +- src/common/system/system.h | 3 ++ src/common/system/system_linux.cpp | 13 ++++++++ src/common/system/system_linux.h | 1 + src/common/system/system_other.cpp | 5 +++ src/common/system/system_other.h | 1 + src/common/system/system_windows.cpp | 5 +++ src/common/system/system_windows.h | 1 + test/unit/app/app_test.cpp | 18 ++++++++--- 10 files changed, 76 insertions(+), 20 deletions(-) diff --git a/src/app/app.cpp b/src/app/app.cpp index 2d460604..b5bd3ca0 100644 --- a/src/app/app.cpp +++ b/src/app/app.cpp @@ -1060,6 +1060,12 @@ int CApplication::Run() MoveMouse(Math::Point(0.5f, 0.5f)); // center mouse on start + SystemTimeStamp *lastLoopTimeStamp = m_systemUtils->CreateTimeStamp(); + SystemTimeStamp *currentTimeStamp = m_systemUtils->CreateTimeStamp(); + SystemTimeStamp *interpolatedTimeStamp = m_systemUtils->CreateTimeStamp(); + m_systemUtils->GetCurrentTimeStamp(lastLoopTimeStamp); + m_systemUtils->CopyTimeStamp(currentTimeStamp, lastLoopTimeStamp); + while (true) { if (m_active) @@ -1158,21 +1164,30 @@ int CApplication::Run() CProfiler::StartPerformanceCounter(PCNT_UPDATE_ALL); - // Prepare and process step simulation event - Event event = CreateUpdateEvent(); - if (event.type != EVENT_NULL && m_controller != nullptr) + // Prepare and process step simulation event(s) + // If game speed is increased then we do extra ticks per loop iteration to improve physics accuracy. + int numTickSlices = static_cast(GetSimulationSpeed()); + if(numTickSlices < 1) numTickSlices = 1; + m_systemUtils->CopyTimeStamp(lastLoopTimeStamp, currentTimeStamp); + m_systemUtils->GetCurrentTimeStamp(currentTimeStamp); + for(int tickSlice = 0; tickSlice < numTickSlices; tickSlice++) { - LogEvent(event); + m_systemUtils->InterpolateTimeStamp(interpolatedTimeStamp, lastLoopTimeStamp, currentTimeStamp, (tickSlice+1)/static_cast(numTickSlices)); + Event event = CreateUpdateEvent(interpolatedTimeStamp); + if (event.type != EVENT_NULL && m_controller != nullptr) + { + LogEvent(event); - m_sound->FrameMove(m_relTime); + m_sound->FrameMove(m_relTime); - CProfiler::StartPerformanceCounter(PCNT_UPDATE_GAME); - m_controller->ProcessEvent(event); - CProfiler::StopPerformanceCounter(PCNT_UPDATE_GAME); + CProfiler::StartPerformanceCounter(PCNT_UPDATE_GAME); + m_controller->ProcessEvent(event); + CProfiler::StopPerformanceCounter(PCNT_UPDATE_GAME); - CProfiler::StartPerformanceCounter(PCNT_UPDATE_ENGINE); - m_engine->FrameUpdate(); - CProfiler::StopPerformanceCounter(PCNT_UPDATE_ENGINE); + CProfiler::StartPerformanceCounter(PCNT_UPDATE_ENGINE); + m_engine->FrameUpdate(); + CProfiler::StopPerformanceCounter(PCNT_UPDATE_ENGINE); + } } CProfiler::StopPerformanceCounter(PCNT_UPDATE_ALL); @@ -1188,6 +1203,10 @@ int CApplication::Run() } end: + m_systemUtils->DestroyTimeStamp(lastLoopTimeStamp); + m_systemUtils->DestroyTimeStamp(currentTimeStamp); + m_systemUtils->DestroyTimeStamp(interpolatedTimeStamp); + return m_exitCode; } @@ -1529,20 +1548,20 @@ void CApplication::SetSimulationSpeed(float speed) { m_simulationSpeed = speed; - m_systemUtils->GetCurrentTimeStamp(m_baseTimeStamp); + m_systemUtils->CopyTimeStamp(m_baseTimeStamp, m_curTimeStamp); m_realAbsTimeBase = m_realAbsTime; m_absTimeBase = m_exactAbsTime; GetLogger()->Info("Simulation speed = %.2f\n", speed); } -Event CApplication::CreateUpdateEvent() +Event CApplication::CreateUpdateEvent(SystemTimeStamp *newTimeStamp) { if (m_simulationSuspended) return Event(EVENT_NULL); m_systemUtils->CopyTimeStamp(m_lastTimeStamp, m_curTimeStamp); - m_systemUtils->GetCurrentTimeStamp(m_curTimeStamp); + m_systemUtils->CopyTimeStamp(m_curTimeStamp, newTimeStamp); long long absDiff = m_systemUtils->TimeStampExactDiff(m_baseTimeStamp, m_curTimeStamp); long long newRealAbsTime = m_realAbsTimeBase + absDiff; diff --git a/src/app/app.h b/src/app/app.h index c0d48a1c..c55eca38 100644 --- a/src/app/app.h +++ b/src/app/app.h @@ -289,7 +289,7 @@ protected: //! If applicable, creates a virtual event to match the changed state as of new event Event CreateVirtualEvent(const Event& sourceEvent); //! Prepares a simulation update event - TEST_VIRTUAL Event CreateUpdateEvent(); + TEST_VIRTUAL Event CreateUpdateEvent(SystemTimeStamp *newTimeStamp); //! Logs debug data for event void LogEvent(const Event& event); diff --git a/src/common/system/system.h b/src/common/system/system.h index 553dc56f..ebc92269 100644 --- a/src/common/system/system.h +++ b/src/common/system/system.h @@ -116,6 +116,9 @@ public: //! Copies the time stamp from \a src to \a dst TEST_VIRTUAL void CopyTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *src); + //! Interpolates between two timestamps. If i=0 then dst=a. If i=1 then dst=b. If i=0.5 then dst is halfway between. + virtual void InterpolateTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *a, SystemTimeStamp *b, float i) = 0; + //! Returns a time stamp associated with current time virtual void GetCurrentTimeStamp(SystemTimeStamp *stamp) = 0; diff --git a/src/common/system/system_linux.cpp b/src/common/system/system_linux.cpp index 9a09b2c3..459c071f 100644 --- a/src/common/system/system_linux.cpp +++ b/src/common/system/system_linux.cpp @@ -83,6 +83,19 @@ SystemDialogResult CSystemUtilsLinux::SystemDialog(SystemDialogType type, const return result; } +void CSystemUtilsLinux::InterpolateTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *a, SystemTimeStamp *b, float i) +{ + long long delta = TimeStampExactDiff(a, b); + delta *= i; // truncates + dst->clockTime.tv_sec = a->clockTime.tv_sec + delta / 1000000000; + dst->clockTime.tv_nsec = a->clockTime.tv_nsec + delta % 1000000000; + if(dst->clockTime.tv_nsec >= 1000000000) + { + dst->clockTime.tv_nsec -= 1000000000; + dst->clockTime.tv_sec++; + } +} + void CSystemUtilsLinux::GetCurrentTimeStamp(SystemTimeStamp *stamp) { clock_gettime(CLOCK_MONOTONIC_RAW, &stamp->clockTime); diff --git a/src/common/system/system_linux.h b/src/common/system/system_linux.h index 6f0c1950..b3446aa6 100644 --- a/src/common/system/system_linux.h +++ b/src/common/system/system_linux.h @@ -40,6 +40,7 @@ public: SystemDialogResult SystemDialog(SystemDialogType type, const std::string& title, const std::string& message) override; + void InterpolateTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *a, SystemTimeStamp *b, float i) override; void GetCurrentTimeStamp(SystemTimeStamp *stamp) override; long long TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after) override; diff --git a/src/common/system/system_other.cpp b/src/common/system/system_other.cpp index d73ce705..865db847 100644 --- a/src/common/system/system_other.cpp +++ b/src/common/system/system_other.cpp @@ -34,6 +34,11 @@ void CSystemUtilsOther::GetCurrentTimeStamp(SystemTimeStamp* stamp) stamp->sdlTicks = SDL_GetTicks(); } +void CSystemUtilsOther::InterpolateTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *a, SystemTimeStamp *b, float i) +{ + dst->sdlTicks = a->sdlTicks + static_cast((b->sdlTicks - a->sdlTicks) * i); +} + long long int CSystemUtilsOther::TimeStampExactDiff(SystemTimeStamp* before, SystemTimeStamp* after) { return (after->sdlTicks - before->sdlTicks) * 1000000ll; diff --git a/src/common/system/system_other.h b/src/common/system/system_other.h index dcec37a6..5964b585 100644 --- a/src/common/system/system_other.h +++ b/src/common/system/system_other.h @@ -46,6 +46,7 @@ public: void Init() override; SystemDialogResult SystemDialog(SystemDialogType type, const std::string& title, const std::string& message) override; + void InterpolateTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *a, SystemTimeStamp *b, float i) override; void GetCurrentTimeStamp(SystemTimeStamp *stamp) override; long long TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after) override; diff --git a/src/common/system/system_windows.cpp b/src/common/system/system_windows.cpp index 6406bee3..413b0575 100644 --- a/src/common/system/system_windows.cpp +++ b/src/common/system/system_windows.cpp @@ -83,6 +83,11 @@ void CSystemUtilsWindows::GetCurrentTimeStamp(SystemTimeStamp* stamp) stamp->counterValue = value.QuadPart; } +void CSystemUtilsWindows::InterpolateTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *a, SystemTimeStamp *b, float i) +{ + dst->counterValue = a->counterValue + static_cast((b->counterValue - a->counterValue) * static_cast(i)); +} + long long int CSystemUtilsWindows::TimeStampExactDiff(SystemTimeStamp* before, SystemTimeStamp* after) { float floatValue = static_cast(after->counterValue - before->counterValue) * (1e9 / static_cast(m_counterFrequency)); diff --git a/src/common/system/system_windows.h b/src/common/system/system_windows.h index 736ab706..4bbd704f 100644 --- a/src/common/system/system_windows.h +++ b/src/common/system/system_windows.h @@ -38,6 +38,7 @@ public: SystemDialogResult SystemDialog(SystemDialogType type, const std::string& title, const std::string& message) override; + void InterpolateTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *a, SystemTimeStamp *b, float i) override; void GetCurrentTimeStamp(SystemTimeStamp *stamp) override; long long TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after) override; diff --git a/test/unit/app/app_test.cpp b/test/unit/app/app_test.cpp index 7258f480..aad94e39 100644 --- a/test/unit/app/app_test.cpp +++ b/test/unit/app/app_test.cpp @@ -55,9 +55,9 @@ public: SDL_Quit(); } - Event CreateUpdateEvent() override + Event CreateUpdateEvent(SystemTimeStamp *timestamp) override { - return CApplication::CreateUpdateEvent(); + return CApplication::CreateUpdateEvent(timestamp); } }; @@ -157,7 +157,9 @@ void CApplicationUT::TestCreateUpdateEvent(long long relTimeExact, long long abs float relTime, float absTime, long long relTimeReal, long long absTimeReal) { - Event event = m_app->CreateUpdateEvent(); + SystemTimeStamp *now = CreateTimeStamp(); + GetCurrentTimeStamp(now); + Event event = m_app->CreateUpdateEvent(now); EXPECT_EQ(EVENT_FRAME, event.type); EXPECT_FLOAT_EQ(relTime, event.rTime); EXPECT_FLOAT_EQ(relTime, m_app->GetRelTime()); @@ -172,7 +174,11 @@ void CApplicationUT::TestCreateUpdateEvent(long long relTimeExact, long long abs TEST_F(CApplicationUT, UpdateEventTimeCalculation_SimulationSuspended) { m_app->SuspendSimulation(); - Event event = m_app->CreateUpdateEvent(); + + SystemTimeStamp *now = CreateTimeStamp(); + GetCurrentTimeStamp(now); + Event event = m_app->CreateUpdateEvent(now); + EXPECT_EQ(EVENT_NULL, event.type); } @@ -224,7 +230,9 @@ TEST_F(CApplicationUT, UpdateEventTimeCalculation_NegativeTimeOperation) NextInstant(-1111); - Event event = m_app->CreateUpdateEvent(); + SystemTimeStamp *now = CreateTimeStamp(); + GetCurrentTimeStamp(now); + Event event = m_app->CreateUpdateEvent(now); EXPECT_EQ(EVENT_NULL, event.type); } From a2c62a9da6f2abe6415b60b4800cc16793b56bd4 Mon Sep 17 00:00:00 2001 From: Fiftytwo Date: Mon, 13 Jul 2020 19:44:50 +0200 Subject: [PATCH 16/98] Make Heavy bots destroy bushes on contact --- src/graphics/engine/particle.cpp | 1 + src/graphics/engine/pyro.cpp | 22 ++++++++++++++++++++-- src/graphics/engine/pyro_type.h | 1 + src/object/interface/destroyable_object.h | 1 + src/object/old_object.cpp | 21 +++++++++++++++++++++ src/physics/physics.cpp | 14 ++++++++++++++ 6 files changed, 58 insertions(+), 2 deletions(-) diff --git a/src/graphics/engine/particle.cpp b/src/graphics/engine/particle.cpp index 00a1d863..fbbd59b0 100644 --- a/src/graphics/engine/particle.cpp +++ b/src/graphics/engine/particle.cpp @@ -3543,6 +3543,7 @@ CObject* CParticle::SearchObjectGun(Math::Vector old, Math::Vector pos, continue; } if (!obj->Implements(ObjectInterfaceType::Damageable) && !obj->IsBulletWall()) continue; + if (obj->Implements(ObjectInterfaceType::Jostleable)) continue; Math::Vector oPos = obj->GetPosition(); diff --git a/src/graphics/engine/pyro.cpp b/src/graphics/engine/pyro.cpp index 2813db56..a8ce0fe2 100644 --- a/src/graphics/engine/pyro.cpp +++ b/src/graphics/engine/pyro.cpp @@ -356,6 +356,12 @@ bool CPyro::Create(PyroType type, CObject* obj, float force) if (oType == OBJECT_APOLLO2) limit = 2.0f; m_speed = 1.0f/limit; } + if ( m_type == PT_SQUASH ) + { + m_speed = 1.0f/2.0f; + m_object->SetLock(true); + } + if ( m_type == PT_EXPLOT || m_type == PT_EXPLOO || @@ -399,7 +405,8 @@ bool CPyro::Create(PyroType type, CObject* obj, float force) if ( m_type != PT_FRAGV && m_type != PT_EGG && m_type != PT_WIN && - m_type != PT_LOST ) + m_type != PT_LOST && + m_type != PT_SQUASH) { float h = 40.0f; if ( m_type == PT_FRAGO || @@ -454,7 +461,8 @@ bool CPyro::Create(PyroType type, CObject* obj, float force) m_type != PT_FLCREATE && m_type != PT_FLDELETE && m_type != PT_RESET && - m_type != PT_FINDING ) + m_type != PT_FINDING && + m_type != PT_SQUASH ) { m_camera->StartEffect(CAM_EFFECT_EXPLO, m_pos, force); } @@ -1049,6 +1057,11 @@ bool CPyro::EventProcess(const Event &event) } } + if ( m_type == PT_SQUASH && m_object != nullptr ) + { + m_object->SetScaleY(1.0f-sinf(m_progress)*0.5f); + } + if ( (m_type == PT_BURNT || m_type == PT_BURNO) && m_object != nullptr ) { @@ -1229,6 +1242,11 @@ Error CPyro::IsEnded() m_object->SetScale(1.0f); } + if ( m_type == PT_SQUASH ) + { + m_object->SetType(OBJECT_PLANT19); + } + if ( m_lightRank != -1 ) { m_lightMan->DeleteLight(m_lightRank); diff --git a/src/graphics/engine/pyro_type.h b/src/graphics/engine/pyro_type.h index d414ce93..bc6a8014 100644 --- a/src/graphics/engine/pyro_type.h +++ b/src/graphics/engine/pyro_type.h @@ -59,6 +59,7 @@ enum PyroType PT_DEADW = 25, //! < drowning death PT_FINDING = 26, //! < object discovered PT_FRAGV = 27, //! < fragmentation of plant object + PT_SQUASH = 28, //! < flattening plants }; } // namespace Gfx diff --git a/src/object/interface/destroyable_object.h b/src/object/interface/destroyable_object.h index a81411a2..b102e64e 100644 --- a/src/object/interface/destroyable_object.h +++ b/src/object/interface/destroyable_object.h @@ -33,6 +33,7 @@ enum class DestructionType Burn = 3, //!< burning Drowned = 4, //!< drowned (only for Me) Win = 5, //!< used when removing objects from a team that won + Squash = 6, //!< flatten }; /** diff --git a/src/object/old_object.cpp b/src/object/old_object.cpp index 0e8fb670..ec4526ba 100644 --- a/src/object/old_object.cpp +++ b/src/object/old_object.cpp @@ -351,6 +351,7 @@ bool COldObject::DamageObject(DamageType type, float force, CObject* killer) assert(!Implements(ObjectInterfaceType::Destroyable) || Implements(ObjectInterfaceType::Shielded) || Implements(ObjectInterfaceType::Fragile)); if ( IsDying() ) return false; + if ( Implements(ObjectInterfaceType::Jostleable) ) return false; if ( m_type == OBJECT_ANT || m_type == OBJECT_WORM || @@ -569,6 +570,11 @@ void COldObject::DestroyObject(DestructionType type, CObject* killer) { pyroType = Gfx::PT_WPCHECK; } + else if ( type == DestructionType::Squash ) + { + pyroType = Gfx::PT_SQUASH; + DeleteAllCrashSpheres(); + } assert(pyroType != Gfx::PT_NULL); if (pyroType == Gfx::PT_FRAGT || pyroType == Gfx::PT_FRAGO || @@ -879,6 +885,21 @@ void COldObject::SetType(ObjectType type) m_implementedInterfaces[static_cast(ObjectInterfaceType::Fragile)] = true; m_implementedInterfaces[static_cast(ObjectInterfaceType::Shielded)] = false; } + else if (m_type == OBJECT_PLANT0 || + m_type == OBJECT_PLANT1 || + m_type == OBJECT_PLANT2 || + m_type == OBJECT_PLANT3 || + m_type == OBJECT_PLANT4 || + m_type == OBJECT_PLANT15 || + m_type == OBJECT_PLANT16 || + m_type == OBJECT_PLANT17 || + m_type == OBJECT_PLANT18 ) + { + m_implementedInterfaces[static_cast(ObjectInterfaceType::Damageable)] = true; + m_implementedInterfaces[static_cast(ObjectInterfaceType::Destroyable)] = true; + m_implementedInterfaces[static_cast(ObjectInterfaceType::Fragile)] = true; + m_implementedInterfaces[static_cast(ObjectInterfaceType::Shielded)] = false; + } else { m_implementedInterfaces[static_cast(ObjectInterfaceType::Damageable)] = false; diff --git a/src/physics/physics.cpp b/src/physics/physics.cpp index 753881cf..45d94a12 100644 --- a/src/physics/physics.cpp +++ b/src/physics/physics.cpp @@ -2794,6 +2794,20 @@ bool CPhysics::ExploOther(ObjectType iType, } } + if((oType == OBJECT_PLANT0 || + oType == OBJECT_PLANT1 || + oType == OBJECT_PLANT2 || + oType == OBJECT_PLANT3 || + oType == OBJECT_PLANT4 || + oType == OBJECT_PLANT15 || + oType == OBJECT_PLANT16 || + oType == OBJECT_PLANT17 || + oType == OBJECT_PLANT18)&& + GetDriveFromObject(iType)==DriveType::Heavy) + { + dynamic_cast(pObj)->DestroyObject(DestructionType::Squash); + } + return false; } From 83a32b36b3a228219e07bd64afab91d8e9e9b955 Mon Sep 17 00:00:00 2001 From: Fiftytwo Date: Mon, 13 Jul 2020 20:27:40 +0200 Subject: [PATCH 17/98] Fix collision persistence of exploding Heavy bots --- src/physics/physics.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/physics/physics.cpp b/src/physics/physics.cpp index 65bebd1b..7dd79633 100644 --- a/src/physics/physics.cpp +++ b/src/physics/physics.cpp @@ -2525,7 +2525,7 @@ int CPhysics::ObjectAdapt(const Math::Vector &pos, const Math::Vector &angle) { if ( pObj == m_object ) continue; // yourself? if (IsObjectBeingTransported(pObj)) continue; - //if ( pObj->Implements(ObjectInterfaceType::Destroyable) && dynamic_cast(pObj)->IsDying() ) continue; // is burning or exploding? + if ( pObj->Implements(ObjectInterfaceType::Destroyable) && dynamic_cast(pObj)->GetDying() == DeathType::Exploding ) continue; // is exploding? oType = pObj->GetType(); if ( oType == OBJECT_TOTO ) continue; From 61126af370a1c854ee0f232408bbdce9f9199ac9 Mon Sep 17 00:00:00 2001 From: MrJohn10 <20319636+MrJohn10@users.noreply.github.com> Date: Tue, 14 Jul 2020 18:32:51 +0200 Subject: [PATCH 18/98] Update contact section in Readme - add Discord server, remove forum and IRC channels (#1328) --- README.md | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/README.md b/README.md index 353dbbf5..a393a47a 100644 --- a/README.md +++ b/README.md @@ -43,9 +43,4 @@ If you want to contribute to the project, see [CONTRIBUTING.md](CONTRIBUTING.md) ## Contact -If you want to help in the project, please contact us on our IRC channels or [our forum](http://colobot.info/forum/). - -### IRC channels - -* [#colobot on Freenode](irc://freenode.net#colobot) - main development channel (English); -* [#colobot on pirc.pl](irc://pirc.pl#colobot) - Polish community channel; +If you want to help in the project, please contact us on our [Discord server](https://discord.gg/56Fm9kb). From f87ae45745ad15d1e12e434502d2074c80a719c9 Mon Sep 17 00:00:00 2001 From: MrSimbax Date: Wed, 8 Jul 2020 10:23:25 +0200 Subject: [PATCH 19/98] Update translations Also add a Polish translation for "Mute sounds in background". Related issue: #1316 --- po/colobot.pot | 3 +++ po/cs.po | 12 ++++++++++++ po/de.po | 3 +++ po/fr.po | 3 +++ po/pl.po | 3 +++ po/pt.po | 12 ++++++++++++ po/ru.po | 3 +++ 7 files changed, 39 insertions(+) diff --git a/po/colobot.pot b/po/colobot.pot index 5614aaac..a331ffba 100644 --- a/po/colobot.pot +++ b/po/colobot.pot @@ -415,6 +415,9 @@ msgstr "" msgid "Pause in background\\Pause the game when the window is unfocused" msgstr "" +msgid "Mute sounds in background\\Mute all game sounds when the window is unfocused" +msgstr "" + msgid "Automatic indent\\When program editing" msgstr "" diff --git a/po/cs.po b/po/cs.po index 9111811b..175ab412 100644 --- a/po/cs.po +++ b/po/cs.po @@ -916,6 +916,9 @@ msgstr "Posunout vybraný program níže" msgid "Move selected program up" msgstr "Posunout vybraný program výše" +msgid "Mute sounds in background\\Mute all game sounds when the window is unfocused" +msgstr "" + msgid "Mute\\No sound" msgstr "Ticho\\Bez zvuku" @@ -934,6 +937,9 @@ msgstr "Nový" msgid "New ..." msgstr "Nový..." +msgid "New Folder" +msgstr "" + msgid "New bot available" msgstr "Robot vyroben" @@ -1090,6 +1096,9 @@ msgstr "Zdroj poslední zprávy\\Zobrazí objekt, který poslal poslední zpráv msgid "Original game developed by:" msgstr "Vývojáři původní hry:" +msgid "Overwrite existing file?" +msgstr "" + msgid "Parameters missing" msgstr "Některé parametry nejsou vyplněné" @@ -1387,6 +1396,9 @@ msgstr "Uložit\\Uložit současnou misi" msgid "Save\\Saves the current mission" msgstr "Uložit\\Uloží současnou misi" +msgid "Select Folder" +msgstr "" + msgid "Select the astronaut\\Selects the astronaut" msgstr "Vybrat kosmonauta\\Vybere kosmonauta" diff --git a/po/de.po b/po/de.po index d9c9b2e1..8afe0c8b 100644 --- a/po/de.po +++ b/po/de.po @@ -932,6 +932,9 @@ msgstr "Gewähltes Programm nach unten" msgid "Move selected program up" msgstr "Gewähltes Programm nach oben" +msgid "Mute sounds in background\\Mute all game sounds when the window is unfocused" +msgstr "" + msgid "Mute\\No sound" msgstr "Kein Ton\\Keine Geräusche und Geräuschkulisse" diff --git a/po/fr.po b/po/fr.po index 415a813b..2bfb0c04 100644 --- a/po/fr.po +++ b/po/fr.po @@ -934,6 +934,9 @@ msgstr "Déplace le programme sélectionné vers le bas" msgid "Move selected program up" msgstr "Déplace le programme sélectionné vers le haut" +msgid "Mute sounds in background\\Mute all game sounds when the window is unfocused" +msgstr "" + msgid "Mute\\No sound" msgstr "Silencieux\\Totalement silencieux" diff --git a/po/pl.po b/po/pl.po index 31905276..3cef57ef 100644 --- a/po/pl.po +++ b/po/pl.po @@ -915,6 +915,9 @@ msgstr "Przenieś zaznaczony program w dół" msgid "Move selected program up" msgstr "Przenieś zaznaczony program w górę" +msgid "Mute sounds in background\\Mute all game sounds when the window is unfocused" +msgstr "Cisza, gdy okno jest w tle\\Wycisza wszystkie dźwięki, gdy okno gry stanie się nieaktywne" + msgid "Mute\\No sound" msgstr "Cisza\\Brak dźwięków" diff --git a/po/pt.po b/po/pt.po index 3c0c0bd9..9baba2a9 100644 --- a/po/pt.po +++ b/po/pt.po @@ -929,6 +929,9 @@ msgstr "Move o programa selecionado para baixo" msgid "Move selected program up" msgstr "Move o programa selecionado para cima" +msgid "Mute sounds in background\\Mute all game sounds when the window is unfocused" +msgstr "" + msgid "Mute\\No sound" msgstr "Mudo\\Sem som" @@ -947,6 +950,9 @@ msgstr "Novo" msgid "New ..." msgstr "Novo ..." +msgid "New Folder" +msgstr "" + msgid "New bot available" msgstr "Novo robô disponível" @@ -1103,6 +1109,9 @@ msgstr "Origem da última mensagem\\Mostra de onde a última mensagem foi enviad msgid "Original game developed by:" msgstr "Jogo original desenvolvido por:" +msgid "Overwrite existing file?" +msgstr "" + msgid "Parameters missing" msgstr "Parâmetros ausentes" @@ -1401,6 +1410,9 @@ msgstr "Salvar\\Salve a missão atual" msgid "Save\\Saves the current mission" msgstr "Salvar\\Salva a missão atual" +msgid "Select Folder" +msgstr "" + msgid "Select the astronaut\\Selects the astronaut" msgstr "Selecione o astronauta\\Seleciona o astronauta" diff --git a/po/ru.po b/po/ru.po index 5266520d..4e3f371b 100644 --- a/po/ru.po +++ b/po/ru.po @@ -940,6 +940,9 @@ msgstr "Изменить выбранную программу" msgid "Move selected program up" msgstr "Изменить выбранную программу" +msgid "Mute sounds in background\\Mute all game sounds when the window is unfocused" +msgstr "" + msgid "Mute\\No sound" msgstr "Без звука\\Без звука" From ac32e4000325dddc2a3704c31226a7c49c5b370c Mon Sep 17 00:00:00 2001 From: Fiftytwo Date: Fri, 17 Jul 2020 03:37:13 +0200 Subject: [PATCH 20/98] Add Ruin, Bush, GraviPlant, and Crystal categories in CBOT --- src/object/object_manager.cpp | 29 ++++++++++++++++++++++++++++- src/script/cbottoken.cpp | 8 ++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/object/object_manager.cpp b/src/object/object_manager.cpp index fd335014..3da2478b 100644 --- a/src/object/object_manager.cpp +++ b/src/object/object_manager.cpp @@ -303,7 +303,7 @@ std::vector CObjectManager::RadarAll(CObject* pThis, Math::Vector this oType == OBJECT_RUINmobiler1 || oType == OBJECT_RUINmobiler2 ) { - oType = OBJECT_RUINmobilew1; // any ruin + oType = OBJECT_RUINmobilew1; // any wreck } if ( oType == OBJECT_BARRIER2 || @@ -313,6 +313,33 @@ std::vector CObjectManager::RadarAll(CObject* pThis, Math::Vector this { oType = OBJECT_BARRIER1; // any barrier } + + if ( oType == OBJECT_RUINdoor || + oType == OBJECT_RUINsupport || + oType == OBJECT_RUINradar || + oType == OBJECT_RUINconvert ) // ruins? + { + oType = OBJECT_RUINfactory; // any ruin + } + + if ( oType == OBJECT_PLANT1 || + oType == OBJECT_PLANT2 || + oType == OBJECT_PLANT3 || + oType == OBJECT_PLANT4 || + oType == OBJECT_PLANT15 || + oType == OBJECT_PLANT16 || + oType == OBJECT_PLANT17 || + oType == OBJECT_PLANT18 ) // bushes? + { + oType = OBJECT_PLANT0; // any bush + } + + if ( oType == OBJECT_QUARTZ1 || + oType == OBJECT_QUARTZ2 || + oType == OBJECT_QUARTZ3 ) // crystals? + { + oType = OBJECT_QUARTZ0; // any crystal + } // END OF TODO } diff --git a/src/script/cbottoken.cpp b/src/script/cbottoken.cpp index 54b4352d..4ccbdda0 100644 --- a/src/script/cbottoken.cpp +++ b/src/script/cbottoken.cpp @@ -125,6 +125,10 @@ const char* GetObjectName(ObjectType type) if ( type == OBJECT_BEE ) return "AlienWasp"; if ( type == OBJECT_WORM ) return "AlienWorm"; if ( type == OBJECT_RUINmobilew1) return "Wreck"; + if ( type == OBJECT_RUINfactory ) return "Ruin"; + if ( type == OBJECT_PLANT0 ) return "Bush"; + if ( type == OBJECT_ROOT5 ) return "GraviPlant"; + if ( type == OBJECT_QUARTZ0 ) return "Crystal"; return ""; } @@ -233,6 +237,10 @@ std::string GetHelpFilename(ObjectType type) if ( type == OBJECT_BEE ) helpfile = "object/wasp"; if ( type == OBJECT_WORM ) helpfile = "object/worm"; if ( type == OBJECT_RUINmobilew1) helpfile = "object/wreck"; + if ( type == OBJECT_RUINfactory ) helpfile = "object/ruin"; + if ( type == OBJECT_PLANT0 ) helpfile = "object/bush"; + if ( type == OBJECT_ROOT5 ) helpfile = "object/gravi"; + if ( type == OBJECT_QUARTZ0 ) helpfile = "object/crystal"; if (helpfile.empty()) return ""; From 5f76722ecb7bba6c2739f2498b76f87406a853c3 Mon Sep 17 00:00:00 2001 From: MrSimbax Date: Fri, 17 Jul 2020 17:27:09 +0200 Subject: [PATCH 21/98] Add error dialogs for open path/url buttons --- po/colobot.pot | 14 +++++ po/cs.po | 14 +++++ po/de.po | 14 +++++ po/fr.po | 14 +++++ po/pl.po | 14 +++++ po/pt.po | 35 ++++++++++++ po/ru.po | 14 +++++ src/common/restext.cpp | 4 ++ src/common/restext.h | 4 ++ src/common/system/system.cpp | 8 +-- src/common/system/system.h | 6 ++- src/common/system/system_linux.cpp | 24 ++++----- src/common/system/system_linux.h | 4 +- src/common/system/system_macosx.cpp | 24 ++++----- src/common/system/system_macosx.h | 4 +- src/common/system/system_other.cpp | 10 ---- src/common/system/system_other.h | 3 -- src/common/system/system_windows.cpp | 25 ++++----- src/common/system/system_windows.h | 4 +- src/ui/mainui.cpp | 2 +- src/ui/screen/screen_setup_mods.cpp | 79 ++++++++++++++++++---------- src/ui/screen/screen_setup_mods.h | 5 +- 22 files changed, 233 insertions(+), 92 deletions(-) diff --git a/po/colobot.pot b/po/colobot.pot index 262b251a..a6b61ea3 100644 --- a/po/colobot.pot +++ b/po/colobot.pot @@ -172,6 +172,20 @@ msgstr "" msgid "This menu is for userlevels from mods, but you didn't install any" msgstr "" +msgid "Could not open the file explorer!" +msgstr "" + +#, c-format +msgid "The path %s could not be opened in a file explorer." +msgstr "" + +msgid "Could not open the web browser!" +msgstr "" + +#, c-format +msgid "The address %s could not be opened in a web browser." +msgstr "" + msgid "Keyword help(\\key cbot;)" msgstr "" diff --git a/po/cs.po b/po/cs.po index 0d4d482b..7fff13fe 100644 --- a/po/cs.po +++ b/po/cs.po @@ -440,6 +440,12 @@ msgstr "Kopírovat" msgid "Copy (Ctrl+C)" msgstr "Kopírovat (Ctrl+C)" +msgid "Could not open the file explorer!" +msgstr "" + +msgid "Could not open the web browser!" +msgstr "" + msgid "Current mission saved" msgstr "Současná mise uložena" @@ -1555,6 +1561,10 @@ msgstr "Filtrování textur\\Filtrování textur" msgid "Textures" msgstr "Textury" +#, c-format +msgid "The address %s could not be opened in a web browser." +msgstr "" + msgid "The battle has ended" msgstr "Souboj skončil" @@ -1567,6 +1577,10 @@ msgstr "Funkce nevrátila žádnou hodnotu" msgid "The mission is not accomplished yet (press \\key help; for more details)" msgstr "Mise ještě nebyla splněna (pro podrobnosti stiskněte \\key help;)" +#, c-format +msgid "The path %s could not be opened in a file explorer." +msgstr "" + msgid "The types of the two operands are incompatible" msgstr "Operaci nelze provést s operandy těchto dvou typů" diff --git a/po/de.po b/po/de.po index b03c22ab..702bab19 100644 --- a/po/de.po +++ b/po/de.po @@ -441,6 +441,12 @@ msgstr "Kopieren" msgid "Copy (Ctrl+C)" msgstr "Kopieren (Ctrl+C)" +msgid "Could not open the file explorer!" +msgstr "" + +msgid "Could not open the web browser!" +msgstr "" + msgid "Current mission saved" msgstr "Mission gespeichert" @@ -1572,6 +1578,10 @@ msgstr "Texturfilterung\\Texturfilterung" msgid "Textures" msgstr "Texturen" +#, c-format +msgid "The address %s could not be opened in a web browser." +msgstr "" + msgid "The battle has ended" msgstr "" @@ -1584,6 +1594,10 @@ msgstr "Die Funktion hat kein Ergebnis zurückgegeben" msgid "The mission is not accomplished yet (press \\key help; for more details)" msgstr "Mission noch nicht beendet (Drücken Sie auf \\key help; für weitere Informationen)" +#, c-format +msgid "The path %s could not be opened in a file explorer." +msgstr "" + msgid "The types of the two operands are incompatible" msgstr "Die zwei Operanden sind nicht kompatibel" diff --git a/po/fr.po b/po/fr.po index 6c49754a..dcb5d42e 100644 --- a/po/fr.po +++ b/po/fr.po @@ -443,6 +443,12 @@ msgstr "Copier" msgid "Copy (Ctrl+C)" msgstr "Copier (Ctrl+C)" +msgid "Could not open the file explorer!" +msgstr "" + +msgid "Could not open the web browser!" +msgstr "" + msgid "Current mission saved" msgstr "Enregistrement effectué" @@ -1574,6 +1580,10 @@ msgstr "Filtrage de textures\\Filtrage de textures" msgid "Textures" msgstr "Textures" +#, c-format +msgid "The address %s could not be opened in a web browser." +msgstr "" + msgid "The battle has ended" msgstr "La bataille est terminée" @@ -1586,6 +1596,10 @@ msgstr "La fonction n'a pas retourné de résultat" msgid "The mission is not accomplished yet (press \\key help; for more details)" msgstr "La mission n'est pas terminée (appuyez sur \\key help; pour plus de détails)" +#, c-format +msgid "The path %s could not be opened in a file explorer." +msgstr "" + msgid "The types of the two operands are incompatible" msgstr "Les deux opérandes ne sont pas de types compatibles" diff --git a/po/pl.po b/po/pl.po index 7c90d67f..9535ab56 100644 --- a/po/pl.po +++ b/po/pl.po @@ -439,6 +439,12 @@ msgstr "Kopiuj" msgid "Copy (Ctrl+C)" msgstr "Kopiuj (Ctrl+C)" +msgid "Could not open the file explorer!" +msgstr "Nie udało się otworzyć przeglądarki plików!" + +msgid "Could not open the web browser!" +msgstr "Nie udało się otworzyć przeglądarki internetowej!" + msgid "Current mission saved" msgstr "Bieżąca misja zapisana" @@ -1554,6 +1560,10 @@ msgstr "Filtrowanie tekstur\\Filtrowanie tekstur" msgid "Textures" msgstr "Tekstury" +#, c-format +msgid "The address %s could not be opened in a web browser." +msgstr "Nie udało się otworzyć adresu %s w przeglądarce internetowej." + msgid "The battle has ended" msgstr "Bitwa zakończyła się" @@ -1566,6 +1576,10 @@ msgstr "Funkcja nie zwróciła żadnej wartości" msgid "The mission is not accomplished yet (press \\key help; for more details)" msgstr "Misja nie jest wypełniona (naciśnij \\key help; aby uzyskać szczegóły)" +#, c-format +msgid "The path %s could not be opened in a file explorer." +msgstr "Nie udało się otworzyć ścieżki %s w przeglądarce plików." + msgid "The types of the two operands are incompatible" msgstr "Niezgodne typy operatorów" diff --git a/po/pt.po b/po/pt.po index 9baba2a9..159dd313 100644 --- a/po/pt.po +++ b/po/pt.po @@ -438,6 +438,12 @@ msgstr "Copiar" msgid "Copy (Ctrl+C)" msgstr "Copiar (Ctrl+C)" +msgid "Could not open the file explorer!" +msgstr "" + +msgid "Could not open the web browser!" +msgstr "" + msgid "Current mission saved" msgstr "Missão atual salva" @@ -843,12 +849,18 @@ msgstr "Lista das missões salvas" msgid "Load a saved mission" msgstr "Carregar uma missão salva" +msgid "Load\\Load Mod" +msgstr "" + msgid "Load\\Load a saved mission" msgstr "Carregar\\Carregar uma missão salva" msgid "Load\\Loads the selected mission" msgstr "Carregar\\Carrega a missão selecionada" +msgid "Loaded Mods:" +msgstr "" + msgid "Loading basic level settings" msgstr "Carregando configurações de nível básico" @@ -917,6 +929,9 @@ msgstr "Lista de missões neste planeta:" msgid "Missions\\Select mission" msgstr "Missões\\Selecione uma missão" +msgid "Mods\\Manage installed mods" +msgstr "" + msgid "Mouse inversion X\\Inversion of the scrolling direction on the X axis" msgstr "Inversão de mouse X\\Inverte a direção da rolagem no eixo X" @@ -1085,6 +1100,9 @@ msgstr "Abrir" msgid "Open (Ctrl+O)" msgstr "Abrir (Ctrl+O)" +msgid "Open Directory\\Open Mods directory" +msgstr "" + msgid "Opening brace missing" msgstr "Chave de abertura ausente" @@ -1557,6 +1575,10 @@ msgstr "Filtragem de textura\\Filtragem de textura" msgid "Textures" msgstr "Texturas" +#, c-format +msgid "The address %s could not be opened in a web browser." +msgstr "" + msgid "The battle has ended" msgstr "A batalha acabou" @@ -1569,6 +1591,10 @@ msgstr "A função não retornou nenhum valor" msgid "The mission is not accomplished yet (press \\key help; for more details)" msgstr "A missão não foi completada ainda (pressione \\key help; para mais detalhes)" +#, c-format +msgid "The path %s could not be opened in a file explorer." +msgstr "" + msgid "The types of the two operands are incompatible" msgstr "Os tipos dos dois operandos são incompativeis" @@ -1705,6 +1731,12 @@ msgstr "Sequência de escape desconhecidade" msgid "Unknown function" msgstr "Função desconhecida" +msgid "Unload\\Unload Mod" +msgstr "" + +msgid "Unloaded Mods:" +msgstr "" + msgid "Up (\\key gup;)" msgstr "Cima (\\key gup;)" @@ -1780,6 +1812,9 @@ msgstr "Farejador alado" msgid "Withdraw shield (\\key action;)" msgstr "Retirar escudo (\\key action;)" +msgid "Workshop\\Open Workshop to search Mods" +msgstr "" + msgid "Worm" msgstr "Verme" diff --git a/po/ru.po b/po/ru.po index c062a50b..04d9187a 100644 --- a/po/ru.po +++ b/po/ru.po @@ -446,6 +446,12 @@ msgstr "Копировать" msgid "Copy (Ctrl+C)" msgstr "Копировать (Ctrl+C)" +msgid "Could not open the file explorer!" +msgstr "" + +msgid "Could not open the web browser!" +msgstr "" + msgid "Current mission saved" msgstr "Текущая миссия сохранена" @@ -1585,6 +1591,10 @@ msgstr "Фильтрация текстур\\Фильтрация текстур msgid "Textures" msgstr "Текстуры" +#, c-format +msgid "The address %s could not be opened in a web browser." +msgstr "" + msgid "The battle has ended" msgstr "" @@ -1597,6 +1607,10 @@ msgstr "Функция не возвратила значения" msgid "The mission is not accomplished yet (press \\key help; for more details)" msgstr "Миссия еще не выполнена (нажмите \\key help; для более подробной информации)" +#, c-format +msgid "The path %s could not be opened in a file explorer." +msgstr "" + msgid "The types of the two operands are incompatible" msgstr "Типы операндов несовместимы" diff --git a/src/common/restext.cpp b/src/common/restext.cpp index 74fb31ed..11270e46 100644 --- a/src/common/restext.cpp +++ b/src/common/restext.cpp @@ -111,6 +111,10 @@ void InitializeRestext() stringsText[RT_DIALOG_OK] = TR("OK"); stringsText[RT_DIALOG_NOUSRLVL_TITLE] = TR("No userlevels installed!"); stringsText[RT_DIALOG_NOUSRLVL_TEXT] = TR("This menu is for userlevels from mods, but you didn't install any"); + stringsText[RT_DIALOG_OPEN_PATH_FAILED_TITLE] = TR("Could not open the file explorer!"); + stringsText[RT_DIALOG_OPEN_PATH_FAILED_TEXT] = TR("The path %s could not be opened in a file explorer."); + stringsText[RT_DIALOG_OPEN_WEBSITE_FAILED_TITLE] = TR("Could not open the web browser!"); + stringsText[RT_DIALOG_OPEN_WEBSITE_FAILED_TEXT] = TR("The address %s could not be opened in a web browser."); stringsText[RT_STUDIO_LISTTT] = TR("Keyword help(\\key cbot;)"); stringsText[RT_STUDIO_COMPOK] = TR("Compilation ok (0 errors)"); diff --git a/src/common/restext.h b/src/common/restext.h index 824481d5..9edf4105 100644 --- a/src/common/restext.h +++ b/src/common/restext.h @@ -105,6 +105,10 @@ enum ResTextType RT_DIALOG_OK = 110, RT_DIALOG_NOUSRLVL_TITLE = 111, RT_DIALOG_NOUSRLVL_TEXT = 112, + RT_DIALOG_OPEN_PATH_FAILED_TITLE = 113, + RT_DIALOG_OPEN_PATH_FAILED_TEXT = 114, + RT_DIALOG_OPEN_WEBSITE_FAILED_TITLE = 115, + RT_DIALOG_OPEN_WEBSITE_FAILED_TEXT = 116, RT_STUDIO_LISTTT = 120, RT_STUDIO_COMPOK = 121, diff --git a/src/common/system/system.cpp b/src/common/system/system.cpp index f1ede192..b4893655 100644 --- a/src/common/system/system.cpp +++ b/src/common/system/system.cpp @@ -216,12 +216,12 @@ std::string CSystemUtils::GetEnvVar(const std::string& name) return ""; } -void CSystemUtils::OpenPath(std::string path) +bool CSystemUtils::OpenPath(const std::string& path) { - assert(false); + return false; } -void CSystemUtils::OpenWebsite(std::string website) +bool CSystemUtils::OpenWebsite(const std::string& url) { - assert(false); + return false; } diff --git a/src/common/system/system.h b/src/common/system/system.h index a5e01245..f20ee443 100644 --- a/src/common/system/system.h +++ b/src/common/system/system.h @@ -146,10 +146,12 @@ public: virtual std::string GetEnvVar(const std::string &name); //! Opens a path with default file browser - virtual void OpenPath(std::string path); + /** \returns true if successful */ + virtual bool OpenPath(const std::string& path); //! Opens a website with default web browser - virtual void OpenWebsite(std::string website); + /** \returns true if successful */ + virtual bool OpenWebsite(const std::string& url); //! Sleep for given amount of microseconds virtual void Usleep(int usecs) = 0; diff --git a/src/common/system/system_linux.cpp b/src/common/system/system_linux.cpp index a531e45e..2b7d99fa 100644 --- a/src/common/system/system_linux.cpp +++ b/src/common/system/system_linux.cpp @@ -150,26 +150,26 @@ std::string CSystemUtilsLinux::GetEnvVar(const std::string& name) return ""; } -void CSystemUtilsLinux::OpenPath(std::string path) +bool CSystemUtilsLinux::OpenPath(const std::string& path) { - int result; - - result = system(("xdg-open \""+path+"\"").c_str()); - if (result == -1) + int result = system(("xdg-open \"" + path + "\"").c_str()); + if (result != 0) { - GetLogger()->Error("Failed to open path: %s\n", path.c_str()); + GetLogger()->Error("Failed to open path: %s, error code: %i\n", path.c_str(), result); + return false; } + return true; } -void CSystemUtilsLinux::OpenWebsite(std::string website) +bool CSystemUtilsLinux::OpenWebsite(const std::string& url) { - int result; - - result = system(("xdg-open \""+website+"\"").c_str()); - if (result == -1) + int result = system(("xdg-open \"" + url + "\"").c_str()); + if (result != 0) { - GetLogger()->Error("Failed to open website: %s\n", website.c_str()); + GetLogger()->Error("Failed to open website: %s, error code: %i\n", url.c_str(), result); + return false; } + return true; } void CSystemUtilsLinux::Usleep(int usec) diff --git a/src/common/system/system_linux.h b/src/common/system/system_linux.h index e14da475..6607b150 100644 --- a/src/common/system/system_linux.h +++ b/src/common/system/system_linux.h @@ -48,8 +48,8 @@ public: std::string GetEnvVar(const std::string& name) override; - void OpenPath(std::string path) override; - void OpenWebsite(std::string website) override; + bool OpenPath(const std::string& path) override; + bool OpenWebsite(const std::string& url) override; void Usleep(int usec) override; diff --git a/src/common/system/system_macosx.cpp b/src/common/system/system_macosx.cpp index 761a68ea..d65fb6dc 100644 --- a/src/common/system/system_macosx.cpp +++ b/src/common/system/system_macosx.cpp @@ -119,26 +119,26 @@ std::string CSystemUtilsMacOSX::GetEnvVar(const std::string& str) return std::string(); } -void CSystemUtilsLinux::OpenPath(std::string path) +bool CSystemUtilsMacOSX::OpenPath(const std::string& path) { - int result; - - result = system(("open \""+path+"\"").c_str()); // TODO: Test on macOS - if (result == -1) + int result = system(("open \"" + path + "\"").c_str()); // TODO: Test on macOS + if (result != 0) { - GetLogger()->Error("Failed to open path: %s\n", path.c_str()); + GetLogger()->Error("Failed to open path: %s, error code: %i\n", path.c_str(), result); + return false; } + return true; } -void CSystemUtilsLinux::OpenWebsite(std::string website) +bool CSystemUtilsMacOSX::OpenWebsite(const std::string& url) { - int result; - - result = system(("open \""+website+"\"").c_str()); // TODO: Test on macOS - if (result == -1) + int result = system(("open \"" + url + "\"").c_str()); // TODO: Test on macOS + if (result != 0) { - GetLogger()->Error("Failed to open website: %s\n", website.c_str()); + GetLogger()->Error("Failed to open website: %s, error code: %i\n", website.c_str(), result); + return false; } + return true; } void CSystemUtilsMacOSX::Usleep(int usec) diff --git a/src/common/system/system_macosx.h b/src/common/system/system_macosx.h index 08b7b91e..523e52e8 100644 --- a/src/common/system/system_macosx.h +++ b/src/common/system/system_macosx.h @@ -38,8 +38,8 @@ public: std::string GetEnvVar(const std::string& name) override; - void OpenPath(std::string path) override; - void OpenWebsite(std::string website) override; + bool OpenPath(const std::string& path) override; + bool OpenWebsite(const std::string& url) override; void Usleep(int usec) override; diff --git a/src/common/system/system_other.cpp b/src/common/system/system_other.cpp index 549c9af1..865db847 100644 --- a/src/common/system/system_other.cpp +++ b/src/common/system/system_other.cpp @@ -44,16 +44,6 @@ long long int CSystemUtilsOther::TimeStampExactDiff(SystemTimeStamp* before, Sys return (after->sdlTicks - before->sdlTicks) * 1000000ll; } -void CSystemUtilsOther::OpenPath(std::string path) -{ - // TODO -} - -void CSystemUtilsOther::OpenWebsite(std::string website) -{ - // TODO -} - void CSystemUtilsOther::Usleep(int usec) { SDL_Delay(usec / 1000); // close enough diff --git a/src/common/system/system_other.h b/src/common/system/system_other.h index c27d7d52..5964b585 100644 --- a/src/common/system/system_other.h +++ b/src/common/system/system_other.h @@ -50,9 +50,6 @@ public: void GetCurrentTimeStamp(SystemTimeStamp *stamp) override; long long TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after) override; - void OpenPath(std::string path) override; - void OpenWebsite(std::string website) override; - void Usleep(int usec) override; }; diff --git a/src/common/system/system_windows.cpp b/src/common/system/system_windows.cpp index 21a77aa9..989d359b 100644 --- a/src/common/system/system_windows.cpp +++ b/src/common/system/system_windows.cpp @@ -21,6 +21,7 @@ #include "common/logger.h" +#include #include @@ -152,26 +153,26 @@ std::string CSystemUtilsWindows::GetEnvVar(const std::string& name) } } -void CSystemUtilsWindows::OpenPath(std::string path) +bool CSystemUtilsWindows::OpenPath(const std::string& path) { - int result; - - result = system(("explorer \""+path+"\"").c_str()); // TODO: Test on macOS - if (result == -1) + int result = system(("start explorer \"" + boost::filesystem::path(path).make_preferred().string() + "\"").c_str()); + if (result != 0) { - GetLogger()->Error("Failed to open path: %s\n", path.c_str()); + GetLogger()->Error("Failed to open path: %s, error code: %i\n", path.c_str(), result); + return false; } + return true; } -void CSystemUtilsWindows::OpenWebsite(std::string website) +bool CSystemUtilsWindows::OpenWebsite(const std::string& url) { - int result; - - result = system(("rundll32 url.dll,FileProtocolHandler \""+website+"\"").c_str()); // TODO: Test on macOS - if (result == -1) + int result = system(("rundll32 url.dll,FileProtocolHandler \"" + url + "\"").c_str()); + if (result != 0) { - GetLogger()->Error("Failed to open website: %s\n", website.c_str()); + GetLogger()->Error("Failed to open website: %s, error code: %i\n", url.c_str(), result); + return false; } + return true; } void CSystemUtilsWindows::Usleep(int usec) diff --git a/src/common/system/system_windows.h b/src/common/system/system_windows.h index e3b98f20..90ef6b91 100644 --- a/src/common/system/system_windows.h +++ b/src/common/system/system_windows.h @@ -46,8 +46,8 @@ public: std::string GetEnvVar(const std::string& name) override; - void OpenPath(std::string path) override; - void OpenWebsite(std::string website) override; + bool OpenPath(const std::string& path) override; + bool OpenWebsite(const std::string& url) override; void Usleep(int usec) override; diff --git a/src/ui/mainui.cpp b/src/ui/mainui.cpp index ab737e12..14fc454d 100644 --- a/src/ui/mainui.cpp +++ b/src/ui/mainui.cpp @@ -85,7 +85,7 @@ CMainUserInterface::CMainUserInterface() m_screenSetupDisplay = MakeUnique(); m_screenSetupGame = MakeUnique(); m_screenSetupGraphics = MakeUnique(); - m_screenSetupMods = MakeUnique(); + m_screenSetupMods = MakeUnique(m_dialog.get()); m_screenSetupSound = MakeUnique(); m_screenMainMenu = MakeUnique(); m_screenPlayerSelect = MakeUnique(m_dialog.get()); diff --git a/src/ui/screen/screen_setup_mods.cpp b/src/ui/screen/screen_setup_mods.cpp index 3779ee32..9415ad24 100644 --- a/src/ui/screen/screen_setup_mods.cpp +++ b/src/ui/screen/screen_setup_mods.cpp @@ -28,6 +28,7 @@ #include "common/config.h" #include "common/logger.h" #include "common/settings.h" +#include "common/stringutils.h" #include "common/resources/resourcemanager.h" #include "level/parser/parser.h" @@ -48,7 +49,8 @@ using namespace boost::filesystem; namespace Ui { -CScreenSetupMods::CScreenSetupMods() +CScreenSetupMods::CScreenSetupMods(CMainDialog* mainDialog) + : m_dialog(mainDialog) { } @@ -131,7 +133,9 @@ bool CScreenSetupMods::EventProcess(const Event &event) CWindow* pw; CButton* pb; CList* pl; - std::string modName, modPath, website = "https://www.moddb.com/games/colobot-gold-edition"; + std::string modName; + const std::string website = "https://www.moddb.com/games/colobot-gold-edition"; + const std::string modDir = CResourceManager::GetSaveLocation() + "/" + "mods"; auto systemUtils = CSystemUtils::Create(); // platform-specific utils if (!CScreenSetup::EventProcess(event)) return false; @@ -139,33 +143,28 @@ bool CScreenSetupMods::EventProcess(const Event &event) pw = static_cast(m_interface->SearchControl(EVENT_WINDOW5)); if ( pw == nullptr ) return false; - if (event.type == EVENT_INTERFACE_LOAD) - { - pl = static_cast(pw->SearchControl(EVENT_INTERFACE_MODS_UNLOADED)); - if ( pl == nullptr ) return false; - modName = pl->GetItemName(pl->GetSelect()); - LoadMod(modName); - - m_app->Reload(); - m_main->ChangePhase(PHASE_SETUPm); - } - if (event.type == EVENT_INTERFACE_UNLOAD) - { - pl = static_cast(pw->SearchControl(EVENT_INTERFACE_MODS_LOADED)); - if ( pl == nullptr ) return false; - modName = pl->GetItemName(pl->GetSelect()); - UnloadMod(modName); - - m_app->Reload(); - m_main->ChangePhase(PHASE_SETUPm); - } - if (event.type == EVENT_INTERFACE_MODS_DIR) - { - modPath = CResourceManager::GetSaveLocation() + "/" + "mods"; - systemUtils->OpenPath(modPath); - } switch (event.type) { + case EVENT_INTERFACE_LOAD: + pl = static_cast(pw->SearchControl(EVENT_INTERFACE_MODS_UNLOADED)); + if (pl == nullptr) return false; + modName = pl->GetItemName(pl->GetSelect()); + LoadMod(modName); + + m_app->Reload(); + m_main->ChangePhase(PHASE_SETUPm); + break; + + case EVENT_INTERFACE_UNLOAD: + pl = static_cast(pw->SearchControl(EVENT_INTERFACE_MODS_LOADED)); + if (pl == nullptr) return false; + modName = pl->GetItemName(pl->GetSelect()); + UnloadMod(modName); + + m_app->Reload(); + m_main->ChangePhase(PHASE_SETUPm); + break; + case EVENT_INTERFACE_MODS_UNLOADED: pl = static_cast(pw->SearchControl(EVENT_INTERFACE_MODS_LOADED)); if ( pl == nullptr ) break; @@ -194,9 +193,31 @@ bool CScreenSetupMods::EventProcess(const Event &event) pb->SetState(STATE_ENABLE); break; - case EVENT_INTERFACE_WORKSHOP: - systemUtils->OpenWebsite(website); + case EVENT_INTERFACE_MODS_DIR: + if (!systemUtils->OpenPath(modDir)) + { + std::string title, text; + GetResource(RES_TEXT, RT_DIALOG_OPEN_PATH_FAILED_TITLE, title); + GetResource(RES_TEXT, RT_DIALOG_OPEN_PATH_FAILED_TEXT, text); + + // Workaround for how labels treat the \\ character on Windows + std::string modDirWithoutBackSlashes = modDir; + std::replace(modDirWithoutBackSlashes.begin(), modDirWithoutBackSlashes.end(), '\\', '/'); + + m_dialog->StartInformation(title, title, StrUtils::Format(text.c_str(), modDirWithoutBackSlashes.c_str())); + } break; + + case EVENT_INTERFACE_WORKSHOP: + if (!systemUtils->OpenWebsite(website)) + { + std::string title, text; + GetResource(RES_TEXT, RT_DIALOG_OPEN_WEBSITE_FAILED_TITLE, title); + GetResource(RES_TEXT, RT_DIALOG_OPEN_WEBSITE_FAILED_TEXT, text); + m_dialog->StartInformation(title, title, StrUtils::Format(text.c_str(), website.c_str())); + } + break; + default: return true; } diff --git a/src/ui/screen/screen_setup_mods.h b/src/ui/screen/screen_setup_mods.h index e61d75bc..75b8c5a1 100644 --- a/src/ui/screen/screen_setup_mods.h +++ b/src/ui/screen/screen_setup_mods.h @@ -19,6 +19,7 @@ #pragma once +#include "ui/maindialog.h" #include "ui/screen/screen_setup.h" #include @@ -31,7 +32,7 @@ namespace Ui class CScreenSetupMods : public CScreenSetup { public: - CScreenSetupMods(); + CScreenSetupMods(CMainDialog* mainDialog); void SetActive() override; void CreateInterface() override; @@ -44,6 +45,8 @@ protected: void UpdateLoadedModList(); protected: + CMainDialog* m_dialog; + CPathManager* m_pathManager; std::vector m_unloadedModList; std::vector m_loadedModList; From b72bedaf60724a8d6ebf1a61f534736363d01abd Mon Sep 17 00:00:00 2001 From: Fiftytwo Date: Fri, 17 Jul 2020 18:00:36 +0200 Subject: [PATCH 22/98] Add BrownMushroom and GreenMushroom categories in CBOT --- src/script/cbottoken.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/script/cbottoken.cpp b/src/script/cbottoken.cpp index 4ccbdda0..4cdae229 100644 --- a/src/script/cbottoken.cpp +++ b/src/script/cbottoken.cpp @@ -129,6 +129,8 @@ const char* GetObjectName(ObjectType type) if ( type == OBJECT_PLANT0 ) return "Bush"; if ( type == OBJECT_ROOT5 ) return "GraviPlant"; if ( type == OBJECT_QUARTZ0 ) return "Crystal"; + if ( type == OBJECT_MUSHROOM1 ) return "BrownMushroom"; + if ( type == OBJECT_MUSHROOM2 ) return "GreenMushroom"; return ""; } @@ -241,6 +243,8 @@ std::string GetHelpFilename(ObjectType type) if ( type == OBJECT_PLANT0 ) helpfile = "object/bush"; if ( type == OBJECT_ROOT5 ) helpfile = "object/gravi"; if ( type == OBJECT_QUARTZ0 ) helpfile = "object/crystal"; + if ( type == OBJECT_MUSHROOM1 ) helpfile = "object/gremush"; + if ( type == OBJECT_MUSHROOM2 ) helpfile = "object/bromush"; if (helpfile.empty()) return ""; From 95cab790c1f708d1ad92d24db474fdebeac0a563 Mon Sep 17 00:00:00 2001 From: Fiftytwo Date: Fri, 17 Jul 2020 19:33:53 +0200 Subject: [PATCH 23/98] Rename 'freemissions' back to 'free' --- src/level/level_category.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/level/level_category.cpp b/src/level/level_category.cpp index 7ab27d83..95c17526 100644 --- a/src/level/level_category.cpp +++ b/src/level/level_category.cpp @@ -25,7 +25,7 @@ // TODO: I'm not sure about "challenges" + "custom". It may be messing things up already right now. const std::map CATEGORY_DIR_MAP = { { LevelCategory::Missions, "missions" }, - { LevelCategory::FreeGame, "freemissions" }, + { LevelCategory::FreeGame, "free" }, { LevelCategory::Exercises, "exercises" }, { LevelCategory::Challenges, "challenges" }, { LevelCategory::CodeBattles, "battles" }, From 8390d85e4651cb599250436ed114ca3d11425f6a Mon Sep 17 00:00:00 2001 From: MrSimbax Date: Sat, 18 Jul 2020 14:30:50 +0200 Subject: [PATCH 24/98] Refactor the mod manager Moved list of mods logic to a new CModManager class. The list of enabled mods is now managed by a flag instead of directory names of mods. Mods are now disabled by default. Also general cleanup, fixing issues from the code review in https://github.com/colobot/colobot/pull/1191 and fixing linter issues. Regression: the state of enabled/disabled mods is now not persistent. The plan is to use some kind of config file for this. --- src/CMakeLists.txt | 2 + src/app/app.cpp | 62 ++++++------ src/app/app.h | 12 ++- src/app/modman.cpp | 117 +++++++++++++++++++++++ src/app/modman.h | 75 +++++++++++++++ src/app/pathman.cpp | 99 +++++++------------ src/app/pathman.h | 12 +-- src/common/resources/resourcemanager.cpp | 6 ++ src/common/resources/resourcemanager.h | 2 + src/graphics/engine/text.cpp | 6 +- src/ui/mainui.cpp | 2 +- src/ui/screen/screen_setup_mods.cpp | 87 ++++++----------- src/ui/screen/screen_setup_mods.h | 15 ++- 13 files changed, 320 insertions(+), 177 deletions(-) create mode 100644 src/app/modman.cpp create mode 100644 src/app/modman.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2fa18acc..f70489ab 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -145,6 +145,8 @@ set(BASE_SOURCES app/controller.h app/input.cpp app/input.h + app/modman.cpp + app/modman.h app/pathman.cpp app/pathman.h app/pausemanager.cpp diff --git a/src/app/app.cpp b/src/app/app.cpp index d0cb9692..2bb6a805 100644 --- a/src/app/app.cpp +++ b/src/app/app.cpp @@ -21,6 +21,7 @@ #include "app/controller.h" #include "app/input.h" +#include "app/modman.h" #include "app/pathman.h" #include "common/config_file.h" @@ -113,7 +114,8 @@ CApplication::CApplication(CSystemUtils* systemUtils) m_private(MakeUnique()), m_configFile(MakeUnique()), m_input(MakeUnique()), - m_pathManager(MakeUnique(systemUtils)) + m_pathManager(MakeUnique(systemUtils)), + m_modManager(MakeUnique(this, m_pathManager.get())) { m_exitCode = 0; m_active = false; @@ -220,6 +222,11 @@ CSoundInterface* CApplication::GetSound() return m_sound.get(); } +CModManager* CApplication::GetModManager() +{ + return m_modManager.get(); +} + void CApplication::LoadEnvironmentVariables() { auto dataDir = m_systemUtils->GetEnvVar("COLOBOT_DATA_DIR"); @@ -513,6 +520,8 @@ bool CApplication::Create() GetLogger()->Warn("Config could not be loaded. Default values will be used!\n"); } + m_modManager->ReinitMods(); + // Create the sound instance. #ifdef OPENAL_SOUND if (!m_headless) @@ -698,21 +707,7 @@ bool CApplication::Create() // Create the robot application. m_controller = MakeUnique(); - CThread musicLoadThread([this]() - { - GetLogger()->Debug("Cache sounds...\n"); - SystemTimeStamp* musicLoadStart = m_systemUtils->CreateTimeStamp(); - m_systemUtils->GetCurrentTimeStamp(musicLoadStart); - - m_sound->CacheAll(); - - SystemTimeStamp* musicLoadEnd = m_systemUtils->CreateTimeStamp(); - m_systemUtils->GetCurrentTimeStamp(musicLoadEnd); - float musicLoadTime = m_systemUtils->TimeStampDiff(musicLoadStart, musicLoadEnd, STU_MSEC); - GetLogger()->Debug("Sound loading took %.2f ms\n", musicLoadTime); - }, - "Sound loading thread"); - musicLoadThread.Start(); + StartLoadingMusic(); if (m_runSceneCategory == LevelCategory::Max) m_controller->StartApp(); @@ -726,22 +721,11 @@ bool CApplication::Create() return true; } -void CApplication::Reload() +void CApplication::ReloadResources() { - m_sound->Create(); + GetLogger()->Info("Reloading resources\n"); m_engine->ReloadAllTextures(); - CThread musicLoadThread([this]() - { - SystemTimeStamp* musicLoadStart = m_systemUtils->CreateTimeStamp(); - m_systemUtils->GetCurrentTimeStamp(musicLoadStart); - m_sound->CacheAll(); - SystemTimeStamp* musicLoadEnd = m_systemUtils->CreateTimeStamp(); - m_systemUtils->GetCurrentTimeStamp(musicLoadEnd); - float musicLoadTime = m_systemUtils->TimeStampDiff(musicLoadStart, musicLoadEnd, STU_MSEC); - GetLogger()->Debug("Sound loading took %.2f ms\n", musicLoadTime); - }, - "Sound loading thread"); - musicLoadThread.Start(); + StartLoadingMusic(); m_controller->GetRobotMain()->UpdateCustomLevelList(); } @@ -1559,6 +1543,24 @@ void CApplication::InternalResumeSimulation() m_absTimeBase = m_exactAbsTime; } +void CApplication::StartLoadingMusic() +{ + CThread musicLoadThread([this]() + { + GetLogger()->Debug("Cache sounds...\n"); + SystemTimeStamp* musicLoadStart = m_systemUtils->CreateTimeStamp(); + m_systemUtils->GetCurrentTimeStamp(musicLoadStart); + + m_sound->CacheAll(); + + SystemTimeStamp* musicLoadEnd = m_systemUtils->CreateTimeStamp(); + m_systemUtils->GetCurrentTimeStamp(musicLoadEnd); + float musicLoadTime = m_systemUtils->TimeStampDiff(musicLoadStart, musicLoadEnd, STU_MSEC); + GetLogger()->Debug("Sound loading took %.2f ms\n", musicLoadTime); + }, "Sound loading thread"); + musicLoadThread.Start(); +} + bool CApplication::GetSimulationSuspended() const { return m_simulationSuspended; diff --git a/src/app/app.h b/src/app/app.h index c45e6320..af385cf2 100644 --- a/src/app/app.h +++ b/src/app/app.h @@ -42,6 +42,7 @@ class CEventQueue; class CController; class CSoundInterface; class CInput; +class CModManager; class CPathManager; class CConfigFile; class CSystemUtils; @@ -162,6 +163,8 @@ public: CEventQueue* GetEventQueue(); //! Returns the sound subsystem CSoundInterface* GetSound(); + //! Returns the mod manager + CModManager* GetModManager(); public: //! Loads some data from environment variables @@ -170,8 +173,8 @@ public: ParseArgsStatus ParseArguments(int argc, char *argv[]); //! Initializes the application bool Create(); - //! Reloads the application - void Reload(); + //! Reloads the application resources, e.g. mods + void ReloadResources(); //! Main event loop int Run(); //! Returns the code to be returned at main() exit @@ -303,6 +306,9 @@ protected: //! Internal procedure to reset time counters void InternalResumeSimulation(); + //! Loads music in a new thread + void StartLoadingMusic(); + protected: //! System utils instance CSystemUtils* m_systemUtils; @@ -324,6 +330,8 @@ protected: std::unique_ptr m_input; //! Path manager std::unique_ptr m_pathManager; + //! Mod manager + std::unique_ptr m_modManager; //! Code to return at exit int m_exitCode; diff --git a/src/app/modman.cpp b/src/app/modman.cpp new file mode 100644 index 00000000..e86edb5f --- /dev/null +++ b/src/app/modman.cpp @@ -0,0 +1,117 @@ +/* + * This file is part of the Colobot: Gold Edition source code + * Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam + * http://epsitec.ch; http://colobot.info; http://github.com/colobot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#include "modman.h" + +//TODO: clean up includes +#include "common/config.h" + +#include "app/app.h" +#include "app/pathman.h" + +#include "common/restext.h" +#include "common/logger.h" +#include "common/settings.h" +#include "common/stringutils.h" + +#include "common/resources/resourcemanager.h" + +#include "common/system/system.h" + +#include +#include +#include + +using namespace boost::filesystem; + +CModManager::CModManager(CApplication* app, CPathManager* pathManager) + : m_app{app}, + m_pathManager{pathManager} +{ +} + +void CModManager::ReinitMods() +{ + m_mods.clear(); + const auto foundMods = m_pathManager->FindMods(); + for (const auto& modPath : foundMods) + { + Mod mod; + mod.name = boost::filesystem::path(modPath).stem().string(); + mod.path = modPath; + mod.enabled = m_pathManager->ModLoaded(mod.path); //TODO: load from some config file + m_mods.push_back(mod); + } +} + +void CModManager::EnableMod(const std::string& modName) +{ + Mod* mod = FindMod(modName); + if (!mod) + { + GetLogger()->Error("Could not enable mod: %s not found\n", modName.c_str()); + return; + } + mod->enabled = true; +} + +void CModManager::DisableMod(const std::string& modName) +{ + Mod* mod = FindMod(modName); + if (!mod) + { + GetLogger()->Error("Could not disable mod: %s not found\n", modName.c_str()); + return; + } + mod->enabled = false; +} + +void CModManager::ReloadMods() +{ + for (const auto& mod : m_mods) + { + bool loaded = m_pathManager->ModLoaded(mod.path); + if (mod.enabled && !loaded) + { + m_pathManager->AddMod(mod.path); + } + else if (!mod.enabled && loaded) + { + m_pathManager->RemoveMod(mod.path); + } + } + m_app->ReloadResources(); +} + +boost::optional CModManager::GetMod(const std::string& modName) +{ + Mod* mod = FindMod(modName); + return mod != nullptr ? *mod : boost::optional(); +} + +const std::vector& CModManager::GetMods() const +{ + return m_mods; +} + +Mod* CModManager::FindMod(const std::string& modName) +{ + auto it = std::find_if(m_mods.begin(), m_mods.end(), [&](Mod& mod) { return mod.name == modName; }); + return it != m_mods.end() ? &(*it) : nullptr; +} diff --git a/src/app/modman.h b/src/app/modman.h new file mode 100644 index 00000000..e1a47467 --- /dev/null +++ b/src/app/modman.h @@ -0,0 +1,75 @@ +/* + * This file is part of the Colobot: Gold Edition source code + * Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam + * http://epsitec.ch; http://colobot.info; http://github.com/colobot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#pragma once + +#include "ui/maindialog.h" + +#include "ui/screen/screen_setup.h" + +#include +#include + +class CPathManager; + +struct Mod +{ + std::string name; + std::string path; + bool enabled = false; + //TODO: add metadata for UI +}; + +/** + * \class CApplication + * \brief Main application + * + * This class handles the list of currently loaded mods. + * + */ +class CModManager +{ +public: + CModManager(CApplication* app, CPathManager* pathManager); + + //! Finds all the mods along with their metadata + void ReinitMods(); + + //! Removes a mod from the list of loaded mods + void EnableMod(const std::string& modName); + + //! Adds a mod to the list of loaded mods + void DisableMod(const std::string& modName); + + //! Reloads application resources so the enabled mods are applied + void ReloadMods(); + + boost::optional GetMod(const std::string& modName); + const std::vector& GetMods() const; + +private: + Mod* FindMod(const std::string& modName); + +private: + CApplication* m_app; + CPathManager* m_pathManager; + + //TODO: better data structure? + std::vector m_mods; +}; diff --git a/src/app/pathman.cpp b/src/app/pathman.cpp index d007b0fd..4c4a1a71 100644 --- a/src/app/pathman.cpp +++ b/src/app/pathman.cpp @@ -41,8 +41,7 @@ CPathManager::CPathManager(CSystemUtils* systemUtils) : m_dataPath(systemUtils->GetDataPath()) , m_langPath(systemUtils->GetLangPath()) , m_savePath(systemUtils->GetSaveDir()) - , m_modAutoloadDir{} - , m_mods{} + , m_modSearchDirs{} { } @@ -65,35 +64,41 @@ void CPathManager::SetSavePath(const std::string &savePath) m_savePath = savePath; } -void CPathManager::AddModAutoloadDir(const std::string &modAutoloadDirPath) +void CPathManager::AddModSearchDir(const std::string &modSearchDirPath) { - m_modAutoloadDir.push_back(modAutoloadDirPath); + m_modSearchDirs.push_back(modSearchDirPath); } void CPathManager::AddMod(const std::string &modPath) { - std::string::size_type enabled; - enabled = modPath.find('~'); - if (enabled == std::string::npos) - { - GetLogger()->Info("Loading mod: '%s'\n", modPath.c_str()); - CResourceManager::AddLocation(modPath, true); - } - else - { - GetLogger()->Info("Found excluded mod: '%s'\n", modPath.c_str()); - } + GetLogger()->Info("Loading mod: '%s'\n", modPath.c_str()); + CResourceManager::AddLocation(modPath, true); } void CPathManager::RemoveMod(const std::string &modPath) { - std::string::size_type enabled; - enabled = modPath.find('~'); - if (enabled == std::string::npos) + GetLogger()->Info("Unloading mod: '%s'\n", modPath.c_str()); + CResourceManager::RemoveLocation(modPath); +} + +bool CPathManager::ModLoaded(const std::string& modPath) +{ + return CResourceManager::LocationExists(modPath); +} + +std::vector CPathManager::FindMods() const +{ + std::vector mods; + GetLogger()->Info("Found mods:\n"); + for (const auto &searchPath : m_modSearchDirs) { - GetLogger()->Info("Unloading mod: '%s'\n", modPath.c_str()); - CResourceManager::RemoveLocation(modPath); + for (const auto &modPath : FindModsInDir(searchPath)) + { + GetLogger()->Info(" * %s\n", modPath.c_str()); + mods.push_back(modPath); + } } + return mods; } const std::string& CPathManager::GetDataPath() @@ -152,58 +157,18 @@ void CPathManager::InitPaths() GetLogger()->Info("Data path: %s\n", m_dataPath.c_str()); GetLogger()->Info("Save path: %s\n", m_savePath.c_str()); - m_modAutoloadDir.push_back(m_dataPath + "/mods"); - m_modAutoloadDir.push_back(m_savePath + "/mods"); + m_modSearchDirs.push_back(m_dataPath + "/mods"); + m_modSearchDirs.push_back(m_savePath + "/mods"); - if (!m_modAutoloadDir.empty()) + if (!m_modSearchDirs.empty()) { - GetLogger()->Info("Mod autoload dirs:\n"); - for(const std::string& modAutoloadDir : m_modAutoloadDir) - GetLogger()->Info(" * %s\n", modAutoloadDir.c_str()); - } - if (!m_mods.empty()) - { - GetLogger()->Info("Mods:\n"); - for(const std::string& modPath : m_mods) - GetLogger()->Info(" * %s\n", modPath.c_str()); + GetLogger()->Info("Mod search dirs:\n"); + for(const std::string& modSearchDir : m_modSearchDirs) + GetLogger()->Info(" * %s\n", modSearchDir.c_str()); } CResourceManager::AddLocation(m_dataPath); - for (const std::string& modAutoloadDir : m_modAutoloadDir) - { - GetLogger()->Trace("Searching for mods in '%s'...\n", modAutoloadDir.c_str()); - for (const std::string& modPath : FindModsInDir(modAutoloadDir)) - { - std::string::size_type enabled; - enabled = modPath.find('~'); - if (enabled == std::string::npos) - { - GetLogger()->Info("Autoloading mod: '%s'\n", modPath.c_str()); - CResourceManager::AddLocation(modPath); - } - else - { - GetLogger()->Info("Found excluded mod: '%s'\n", modPath.c_str()); - } - } - } - - for (const std::string& modPath : m_mods) - { - std::string::size_type enabled; - enabled = modPath.find('~'); - if (enabled == std::string::npos) - { - GetLogger()->Info("Loading mod: '%s'\n", modPath.c_str()); - CResourceManager::AddLocation(modPath); - } - else - { - GetLogger()->Info("Found excluded mod: '%s'\n", modPath.c_str()); - } - } - CResourceManager::SetSaveLocation(m_savePath); CResourceManager::AddLocation(m_savePath); @@ -213,7 +178,7 @@ void CPathManager::InitPaths() GetLogger()->Debug(" * %s\n", path.c_str()); } -std::vector CPathManager::FindModsInDir(const std::string &dir) +std::vector CPathManager::FindModsInDir(const std::string &dir) const { std::vector ret; try diff --git a/src/app/pathman.h b/src/app/pathman.h index 9cd9ffe1..3712d307 100644 --- a/src/app/pathman.h +++ b/src/app/pathman.h @@ -37,9 +37,11 @@ public: void SetDataPath(const std::string &dataPath); void SetLangPath(const std::string &langPath); void SetSavePath(const std::string &savePath); - void AddModAutoloadDir(const std::string &modAutoloadDirPath); + void AddModSearchDir(const std::string &modAutoloadDirPath); void AddMod(const std::string &modPath); void RemoveMod(const std::string &modPath); + bool ModLoaded(const std::string& modPath); + std::vector FindMods() const; const std::string& GetDataPath(); const std::string& GetLangPath(); @@ -52,7 +54,7 @@ public: private: //! Loads all mods from given directory - std::vector FindModsInDir(const std::string &dir); + std::vector FindModsInDir(const std::string &dir) const; private: //! Data path @@ -61,8 +63,6 @@ private: std::string m_langPath; //! Save path std::string m_savePath; - //! Mod autoload paths - std::vector m_modAutoloadDir; - //! Mod paths - std::vector m_mods; + //! Mod search paths + std::vector m_modSearchDirs; }; diff --git a/src/common/resources/resourcemanager.cpp b/src/common/resources/resourcemanager.cpp index b51325b8..bddb5236 100644 --- a/src/common/resources/resourcemanager.cpp +++ b/src/common/resources/resourcemanager.cpp @@ -95,6 +95,12 @@ std::vector CResourceManager::GetLocations() return ret; } +bool CResourceManager::LocationExists(const std::string& location) +{ + auto locations = GetLocations(); + auto it = std::find(locations.cbegin(), locations.cend(), location); + return it != locations.cend(); +} bool CResourceManager::SetSaveLocation(const std::string &location) { diff --git a/src/common/resources/resourcemanager.h b/src/common/resources/resourcemanager.h index 8c09b91a..0a1bca16 100644 --- a/src/common/resources/resourcemanager.h +++ b/src/common/resources/resourcemanager.h @@ -41,6 +41,8 @@ public: static bool RemoveLocation(const std::string &location); //! List all locations in the search path static std::vector GetLocations(); + //! Check if given location is in the search path + static bool LocationExists(const std::string &location); static bool SetSaveLocation(const std::string &location); static std::string GetSaveLocation(); diff --git a/src/graphics/engine/text.cpp b/src/graphics/engine/text.cpp index 4306dae8..a85bd5fd 100644 --- a/src/graphics/engine/text.cpp +++ b/src/graphics/engine/text.cpp @@ -259,10 +259,8 @@ void CText::FlushCache() } } - m_lastCachedFont = nullptr; - m_lastFontType = FONT_COMMON; - m_lastFontSize = 0; - + //TODO: fix this + Destroy(); Create(); } diff --git a/src/ui/mainui.cpp b/src/ui/mainui.cpp index 14fc454d..57436f89 100644 --- a/src/ui/mainui.cpp +++ b/src/ui/mainui.cpp @@ -85,7 +85,7 @@ CMainUserInterface::CMainUserInterface() m_screenSetupDisplay = MakeUnique(); m_screenSetupGame = MakeUnique(); m_screenSetupGraphics = MakeUnique(); - m_screenSetupMods = MakeUnique(m_dialog.get()); + m_screenSetupMods = MakeUnique(m_dialog.get(), m_app->GetModManager()); m_screenSetupSound = MakeUnique(); m_screenMainMenu = MakeUnique(); m_screenPlayerSelect = MakeUnique(m_dialog.get()); diff --git a/src/ui/screen/screen_setup_mods.cpp b/src/ui/screen/screen_setup_mods.cpp index 9415ad24..60e8a47f 100644 --- a/src/ui/screen/screen_setup_mods.cpp +++ b/src/ui/screen/screen_setup_mods.cpp @@ -1,6 +1,6 @@ /* * This file is part of the Colobot: Gold Edition source code - * Copyright (C) 2001-2019, Daniel Roux, EPSITEC SA & TerranovaTeam + * Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam * http://epsitec.ch; http://colobot.info; http://github.com/colobot * * This program is free software: you can redistribute it and/or modify @@ -19,18 +19,20 @@ #include "ui/screen/screen_setup_mods.h" -#include "app/app.h" -#include "app/pathman.h" +#include "common/config.h" -#include "common/system/system.h" +#include "app/app.h" +#include "app/modman.h" #include "common/restext.h" -#include "common/config.h" #include "common/logger.h" #include "common/settings.h" #include "common/stringutils.h" #include "common/resources/resourcemanager.h" + +#include "common/system/system.h" + #include "level/parser/parser.h" #include "ui/controls/button.h" @@ -49,8 +51,9 @@ using namespace boost::filesystem; namespace Ui { -CScreenSetupMods::CScreenSetupMods(CMainDialog* mainDialog) - : m_dialog(mainDialog) +CScreenSetupMods::CScreenSetupMods(CMainDialog* dialog, CModManager* modManager) + : m_dialog(dialog), + m_modManager(modManager) { } @@ -128,6 +131,7 @@ void CScreenSetupMods::CreateInterface() pb->SetState(STATE_SHADOW); pb->ClearState(STATE_ENABLE); } + bool CScreenSetupMods::EventProcess(const Event &event) { CWindow* pw; @@ -135,7 +139,7 @@ bool CScreenSetupMods::EventProcess(const Event &event) CList* pl; std::string modName; const std::string website = "https://www.moddb.com/games/colobot-gold-edition"; - const std::string modDir = CResourceManager::GetSaveLocation() + "/" + "mods"; + const std::string modDir = CResourceManager::GetSaveLocation() + "/mods"; auto systemUtils = CSystemUtils::Create(); // platform-specific utils if (!CScreenSetup::EventProcess(event)) return false; @@ -149,9 +153,10 @@ bool CScreenSetupMods::EventProcess(const Event &event) pl = static_cast(pw->SearchControl(EVENT_INTERFACE_MODS_UNLOADED)); if (pl == nullptr) return false; modName = pl->GetItemName(pl->GetSelect()); - LoadMod(modName); - m_app->Reload(); + m_modManager->EnableMod(modName); + m_modManager->ReloadMods(); + m_main->ChangePhase(PHASE_SETUPm); break; @@ -159,9 +164,10 @@ bool CScreenSetupMods::EventProcess(const Event &event) pl = static_cast(pw->SearchControl(EVENT_INTERFACE_MODS_LOADED)); if (pl == nullptr) return false; modName = pl->GetItemName(pl->GetSelect()); - UnloadMod(modName); - m_app->Reload(); + m_modManager->DisableMod(modName); + m_modManager->ReloadMods(); + m_main->ChangePhase(PHASE_SETUPm); break; @@ -200,7 +206,7 @@ bool CScreenSetupMods::EventProcess(const Event &event) GetResource(RES_TEXT, RT_DIALOG_OPEN_PATH_FAILED_TITLE, title); GetResource(RES_TEXT, RT_DIALOG_OPEN_PATH_FAILED_TEXT, text); - // Workaround for how labels treat the \\ character on Windows + // Workaround for Windows: the label skips everything after the first \\ character std::string modDirWithoutBackSlashes = modDir; std::replace(modDirWithoutBackSlashes.begin(), modDirWithoutBackSlashes.end(), '\\', '/'); @@ -224,34 +230,11 @@ bool CScreenSetupMods::EventProcess(const Event &event) return false; } -void CScreenSetupMods::UnloadMod(std::string modName) -{ - std::string modPath, modPathRaw, disabled = "~"; - - modPathRaw = CResourceManager::GetSaveLocation() + "/" + "mods" + "/"; - modPath = modPathRaw.c_str(); - - m_pathManager->RemoveMod(modPath+modName); - boost::filesystem::rename(modPath+modName, modPath+disabled+modName); -} - -void CScreenSetupMods::LoadMod(std::string modName) -{ - std::string modPath, modPathRaw, disabled = "~"; - - modPathRaw = CResourceManager::GetSaveLocation() + "/" + "mods" + "/"; - modPath = modPathRaw.c_str(); - - boost::filesystem::rename(modPath+disabled+modName, modPath+modName); - m_pathManager->AddMod(modPath+modName); -} - void CScreenSetupMods::UpdateUnloadedModList() { CWindow* pw; CList* pl; int i = 0; - std::string modPath, modPathRaw; directory_iterator end_itr; pw = static_cast(m_interface->SearchControl(EVENT_WINDOW5)); @@ -261,30 +244,22 @@ void CScreenSetupMods::UpdateUnloadedModList() if ( pl == nullptr ) return; pl->Flush(); - modPathRaw = CResourceManager::GetSaveLocation() + "/" + "mods" + "/"; - modPath = modPathRaw.c_str(); - - for (directory_iterator itr(modPath); itr != end_itr; ++itr) + for (const auto& mod : m_modManager->GetMods()) { - std::string modName = itr->path().string(); - boost::erase_all(modName, modPath); - std::string::size_type enabled; - enabled = modName.find('~'); - if (enabled != std::string::npos) + if (!mod.enabled) { - modName.erase(0,1); - pl->SetItemName(i++, modName); + pl->SetItemName(i++, mod.name); } } pl->ShowSelect(false); // shows the selected columns } + void CScreenSetupMods::UpdateLoadedModList() { CWindow* pw; CList* pl; int i = 0; - std::string modPath, modPathRaw; directory_iterator end_itr; pw = static_cast(m_interface->SearchControl(EVENT_WINDOW5)); @@ -294,19 +269,15 @@ void CScreenSetupMods::UpdateLoadedModList() if ( pl == nullptr ) return; pl->Flush(); - modPathRaw = CResourceManager::GetSaveLocation() + "/" + "mods" + "/"; - modPath = modPathRaw.c_str(); - - for (directory_iterator itr(modPath); itr != end_itr; ++itr) + for (const auto& mod : m_modManager->GetMods()) { - std::string modName = itr->path().string(); - boost::erase_all(modName, modPath); - std::string::size_type enabled; - enabled = modName.find('~'); - if (enabled == std::string::npos) - pl->SetItemName(i++, modName); + if (mod.enabled) + { + pl->SetItemName(i++, mod.name); + } } pl->ShowSelect(false); // shows the selected columns } + } // namespace Ui diff --git a/src/ui/screen/screen_setup_mods.h b/src/ui/screen/screen_setup_mods.h index 75b8c5a1..fbe2c6eb 100644 --- a/src/ui/screen/screen_setup_mods.h +++ b/src/ui/screen/screen_setup_mods.h @@ -1,6 +1,6 @@ /* * This file is part of the Colobot: Gold Edition source code - * Copyright (C) 2001-2019, Daniel Roux, EPSITEC SA & TerranovaTeam + * Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam * http://epsitec.ch; http://colobot.info; http://github.com/colobot * * This program is free software: you can redistribute it and/or modify @@ -20,11 +20,12 @@ #pragma once #include "ui/maindialog.h" + #include "ui/screen/screen_setup.h" #include -class CPathManager; +class CModManager; namespace Ui { @@ -32,24 +33,20 @@ namespace Ui class CScreenSetupMods : public CScreenSetup { public: - CScreenSetupMods(CMainDialog* mainDialog); + CScreenSetupMods(CMainDialog* dialog, CModManager* modManager); void SetActive() override; void CreateInterface() override; bool EventProcess(const Event &event) override; protected: - void UnloadMod(std::string ModName); - void LoadMod(std::string ModName); void UpdateUnloadedModList(); void UpdateLoadedModList(); protected: - CMainDialog* m_dialog; + CModManager* m_modManager; - CPathManager* m_pathManager; - std::vector m_unloadedModList; - std::vector m_loadedModList; + CMainDialog* m_dialog; }; } // namespace Ui From dc64b95406a05d211343f88329c636251d354447 Mon Sep 17 00:00:00 2001 From: MrSimbax Date: Sat, 18 Jul 2020 14:47:18 +0200 Subject: [PATCH 25/98] Fix build error --- src/app/pathman.h | 2 +- src/ui/screen/screen_setup_mods.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/pathman.h b/src/app/pathman.h index 3712d307..7726786d 100644 --- a/src/app/pathman.h +++ b/src/app/pathman.h @@ -37,7 +37,7 @@ public: void SetDataPath(const std::string &dataPath); void SetLangPath(const std::string &langPath); void SetSavePath(const std::string &savePath); - void AddModSearchDir(const std::string &modAutoloadDirPath); + void AddModSearchDir(const std::string &modSearchDirPath); void AddMod(const std::string &modPath); void RemoveMod(const std::string &modPath); bool ModLoaded(const std::string& modPath); diff --git a/src/ui/screen/screen_setup_mods.h b/src/ui/screen/screen_setup_mods.h index fbe2c6eb..9098d7d7 100644 --- a/src/ui/screen/screen_setup_mods.h +++ b/src/ui/screen/screen_setup_mods.h @@ -44,9 +44,9 @@ protected: void UpdateLoadedModList(); protected: - CModManager* m_modManager; - CMainDialog* m_dialog; + + CModManager* m_modManager; }; } // namespace Ui From a0635ae400b9a86898e100c7b78312cce5c4dd88 Mon Sep 17 00:00:00 2001 From: MrSimbax Date: Sat, 18 Jul 2020 15:01:36 +0200 Subject: [PATCH 26/98] Fix linter issues --- src/app/app.cpp | 3 ++- src/app/modman.cpp | 4 ++-- src/ui/screen/screen_setup_mods.cpp | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/app/app.cpp b/src/app/app.cpp index 2bb6a805..4f73ae16 100644 --- a/src/app/app.cpp +++ b/src/app/app.cpp @@ -1557,7 +1557,8 @@ void CApplication::StartLoadingMusic() m_systemUtils->GetCurrentTimeStamp(musicLoadEnd); float musicLoadTime = m_systemUtils->TimeStampDiff(musicLoadStart, musicLoadEnd, STU_MSEC); GetLogger()->Debug("Sound loading took %.2f ms\n", musicLoadTime); - }, "Sound loading thread"); + }, + "Sound loading thread"); musicLoadThread.Start(); } diff --git a/src/app/modman.cpp b/src/app/modman.cpp index e86edb5f..b67853ce 100644 --- a/src/app/modman.cpp +++ b/src/app/modman.cpp @@ -17,7 +17,7 @@ * along with this program. If not, see http://gnu.org/licenses */ -#include "modman.h" +#include "app/modman.h" //TODO: clean up includes #include "common/config.h" @@ -25,8 +25,8 @@ #include "app/app.h" #include "app/pathman.h" -#include "common/restext.h" #include "common/logger.h" +#include "common/restext.h" #include "common/settings.h" #include "common/stringutils.h" diff --git a/src/ui/screen/screen_setup_mods.cpp b/src/ui/screen/screen_setup_mods.cpp index 60e8a47f..6fae8151 100644 --- a/src/ui/screen/screen_setup_mods.cpp +++ b/src/ui/screen/screen_setup_mods.cpp @@ -24,8 +24,8 @@ #include "app/app.h" #include "app/modman.h" -#include "common/restext.h" #include "common/logger.h" +#include "common/restext.h" #include "common/settings.h" #include "common/stringutils.h" From 69d2d39c36857a477664e3e94429bf32b4206cb7 Mon Sep 17 00:00:00 2001 From: MrSimbax Date: Sat, 18 Jul 2020 18:06:14 +0200 Subject: [PATCH 27/98] Add ability to use arrays in colobot.ini --- src/common/config_file.h | 76 +++++++++++++++++++++++++++ test/unit/common/colobot.ini | 5 ++ test/unit/common/config_file_test.cpp | 22 ++++++++ 3 files changed, 103 insertions(+) diff --git a/src/common/config_file.h b/src/common/config_file.h index 6fbeae71..6e95f481 100644 --- a/src/common/config_file.h +++ b/src/common/config_file.h @@ -26,9 +26,15 @@ #include "common/singleton.h" +#include "common/logger.h" + #include +#include #include +#include +#include +#include /** @@ -100,6 +106,76 @@ public: */ bool GetBoolProperty(std::string section, std::string key, bool &value); + /** Gets an array of values of type T in section under specified key + * The value separator is ','. + * \a array will only be changed if key exists + * \return return true on success + */ + template + bool SetArrayProperty(std::string section, std::string key, const std::vector& array) + { + try + { + std::string convertedValue = ArrayToString(array); + m_propertyTree.put(section + "." + key, convertedValue); + m_needsSave = true; + } + catch (std::exception & e) + { + GetLogger()->Error("Error on editing config file: %s\n", e.what()); + return false; + } + return true; + } + + /** Sets an array of values of type T in section under specified key. + * The value separator is ','. + * \a array will only be changed if key exists + * \return return true on success + */ + template + bool GetArrayProperty(std::string section, std::string key, std::vector& array) + { + try + { + std::string readValue = m_propertyTree.get(section + "." + key); + std::vector convertedValue = StringToArray(readValue); + array = std::move(convertedValue); + } + catch (std::exception & e) + { + GetLogger()->Log(m_loaded ? LOG_INFO : LOG_TRACE, "Error on parsing config file: %s\n", e.what()); + return false; + } + return true; + } + +private: + template + std::vector StringToArray(const std::string& s) + { + std::vector result; + std::stringstream ss(s); + std::string item; + while (std::getline(ss, item, ',')) + { + result.push_back(boost::lexical_cast(item)); + } + return result; + } + + template + std::string ArrayToString(const std::vector &array) + { + std::ostringstream oss; + if (!array.empty()) + { + std::copy(array.begin(), array.end() - 1, std::ostream_iterator(oss, ",")); + oss << array.back(); + } + return oss.str(); + } + private: boost::property_tree::ptree m_propertyTree; bool m_needsSave; diff --git a/test/unit/common/colobot.ini b/test/unit/common/colobot.ini index c4d21623..7cc649b5 100644 --- a/test/unit/common/colobot.ini +++ b/test/unit/common/colobot.ini @@ -6,3 +6,8 @@ string_value=Hello world [test_int] int_value=42 + +[test_array] +string_array=AAA,Hello world,Gold Edition +int_array=2,3,1 +bool_array=1,0,1 diff --git a/test/unit/common/config_file_test.cpp b/test/unit/common/config_file_test.cpp index fcd8f036..762c3307 100644 --- a/test/unit/common/config_file_test.cpp +++ b/test/unit/common/config_file_test.cpp @@ -52,3 +52,25 @@ TEST_F(CConfigFileTest, ReadTest) ASSERT_TRUE(m_configFile.GetFloatProperty("test_float", "float_value", float_value)); ASSERT_FLOAT_EQ(1.5, float_value); } + +TEST_F(CConfigFileTest, ReadArrayTest) +{ + m_configFile.SetUseCurrentDirectory(true); + + ASSERT_TRUE(m_configFile.Init()); // load colobot.ini file + + std::vector expected_string_values = { "AAA", "Hello world", "Gold Edition" }; + std::vector string_values; + ASSERT_TRUE(m_configFile.GetArrayProperty("test_array", "string_array", string_values)); + ASSERT_EQ(expected_string_values, string_values); + + std::vector expected_int_values = { 2, 3, 1 }; + std::vector int_values; + ASSERT_TRUE(m_configFile.GetArrayProperty("test_array", "int_array", int_values)); + ASSERT_EQ(expected_int_values, int_values); + + std::vector expected_bool_values = { true, false, true }; + std::vector bool_values; + ASSERT_TRUE(m_configFile.GetArrayProperty("test_array", "bool_array", bool_values)); + ASSERT_EQ(expected_bool_values, bool_values); +} From d64d78acfc6a42dd8d22915ccccdeb8191d152ef Mon Sep 17 00:00:00 2001 From: Droog71 <71droog71@gmail.com> Date: Sun, 19 Jul 2020 04:55:55 -0400 Subject: [PATCH 28/98] Fix for issue #1221 (#1230) * Fix for issue #1221 * Removed object array and implemented GetObjectName method in it's place. * Fixed indentation issue. * Fixed white space at end of lines 1571, 1572. --- src/script/scriptfunc.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/script/scriptfunc.cpp b/src/script/scriptfunc.cpp index ba217a55..cc2b2bda 100644 --- a/src/script/scriptfunc.cpp +++ b/src/script/scriptfunc.cpp @@ -1565,7 +1565,11 @@ bool CScriptFunctions::rProduce(CBotVar* var, CBotVar* result, int& exception, v { power = 1.0f; } - object = CObjectManager::GetInstancePointer()->CreateObject(pos, angle, type, power); + bool exists = !std::string(GetObjectName(type)).empty(); //The object type exists in object_type.h + if (exists) + { + object = CObjectManager::GetInstancePointer()->CreateObject(pos, angle, type, power); + } if (object == nullptr) { result->SetValInt(1); // error From 63bf6bed08c8ebe458999e2d544fc93ce1477dc9 Mon Sep 17 00:00:00 2001 From: MrSimbax Date: Sun, 19 Jul 2020 15:02:35 +0200 Subject: [PATCH 29/98] Add saving mods list in colobot.ini --- src/app/app.cpp | 4 +- src/app/modman.cpp | 99 +++++++++++++++++++++++------ src/app/modman.h | 15 +++-- src/app/pathman.cpp | 15 ++++- src/app/pathman.h | 3 + src/ui/screen/screen_setup_mods.cpp | 10 ++- 6 files changed, 118 insertions(+), 28 deletions(-) diff --git a/src/app/app.cpp b/src/app/app.cpp index 4f73ae16..54a14d07 100644 --- a/src/app/app.cpp +++ b/src/app/app.cpp @@ -520,7 +520,9 @@ bool CApplication::Create() GetLogger()->Warn("Config could not be loaded. Default values will be used!\n"); } - m_modManager->ReinitMods(); + m_modManager->FindMods(); + m_modManager->SaveMods(); + m_modManager->UpdatePaths(); // Create the sound instance. #ifdef OPENAL_SOUND diff --git a/src/app/modman.cpp b/src/app/modman.cpp index b67853ce..ef044a8a 100644 --- a/src/app/modman.cpp +++ b/src/app/modman.cpp @@ -19,22 +19,18 @@ #include "app/modman.h" -//TODO: clean up includes #include "common/config.h" #include "app/app.h" #include "app/pathman.h" +#include "common/config_file.h" #include "common/logger.h" -#include "common/restext.h" -#include "common/settings.h" -#include "common/stringutils.h" #include "common/resources/resourcemanager.h" -#include "common/system/system.h" - #include +#include #include #include @@ -46,16 +42,64 @@ CModManager::CModManager(CApplication* app, CPathManager* pathManager) { } -void CModManager::ReinitMods() +void CModManager::FindMods() { m_mods.clear(); - const auto foundMods = m_pathManager->FindMods(); - for (const auto& modPath : foundMods) + + // Load names from the config file + std::vector savedModNames; + GetConfigFile().GetArrayProperty("Mods", "Names", savedModNames); + std::vector savedEnabled; + GetConfigFile().GetArrayProperty("Mods", "Enabled", savedEnabled); + + // Transform the data into Mod structures + m_mods.reserve(savedModNames.size()); + for (int i = 0; i < savedModNames.size(); ++i) { - Mod mod; - mod.name = boost::filesystem::path(modPath).stem().string(); - mod.path = modPath; - mod.enabled = m_pathManager->ModLoaded(mod.path); //TODO: load from some config file + Mod mod{}; + mod.name = savedModNames[i]; + if (i < savedEnabled.size()) + { + mod.enabled = savedEnabled[i]; + } + mod.path = ""; // Find the path later + m_mods.push_back(mod); + } + + // Search the folders for mods + const auto rawPaths = m_pathManager->FindMods(); + std::map modPaths; + for (const auto& path : rawPaths) + { + auto modName = boost::filesystem::path(path).stem().string(); + modPaths.insert(std::make_pair(modName, path)); + } + + // Find paths for already saved mods + auto it = m_mods.begin(); + while (it != m_mods.end()) + { + auto& mod = *it; + const auto pathsIt = modPaths.find(mod.name); + if (pathsIt != modPaths.end()) + { + mod.path = (*pathsIt).second; + modPaths.erase(pathsIt); + ++it; + } + else + { + GetLogger()->Warn("Could not find mod %s, removing it from the list\n", mod.name.c_str()); + it = m_mods.erase(it); + } + } + + // Add the remaining found mods to the end of the list + for (const auto& newMod : modPaths) + { + Mod mod{}; + mod.name = newMod.first; + mod.path = newMod.second; m_mods.push_back(mod); } } @@ -82,23 +126,38 @@ void CModManager::DisableMod(const std::string& modName) mod->enabled = false; } -void CModManager::ReloadMods() +void CModManager::UpdatePaths() { + m_pathManager->RemoveAllMods(); for (const auto& mod : m_mods) { - bool loaded = m_pathManager->ModLoaded(mod.path); - if (mod.enabled && !loaded) + if (mod.enabled) { m_pathManager->AddMod(mod.path); } - else if (!mod.enabled && loaded) - { - m_pathManager->RemoveMod(mod.path); - } } +} + +void CModManager::ReloadResources() +{ m_app->ReloadResources(); } +void CModManager::SaveMods() +{ + std::vector savedNames; + savedNames.reserve(m_mods.size()); + std::transform(m_mods.begin(), m_mods.end(), std::back_inserter(savedNames), [](const Mod& mod) { return mod.name; }); + GetConfigFile().SetArrayProperty("Mods", "Names", savedNames); + + std::vector savedEnabled; + savedEnabled.reserve(m_mods.size()); + std::transform(m_mods.begin(), m_mods.end(), std::back_inserter(savedEnabled), [](const Mod& mod) { return mod.enabled; }); + GetConfigFile().SetArrayProperty("Mods", "Enabled", savedEnabled); + + GetConfigFile().Save(); +} + boost::optional CModManager::GetMod(const std::string& modName) { Mod* mod = FindMod(modName); diff --git a/src/app/modman.h b/src/app/modman.h index e1a47467..5ce3efa2 100644 --- a/src/app/modman.h +++ b/src/app/modman.h @@ -30,8 +30,8 @@ class CPathManager; struct Mod { - std::string name; - std::string path; + std::string name{}; + std::string path{}; bool enabled = false; //TODO: add metadata for UI }; @@ -41,6 +41,7 @@ struct Mod * \brief Main application * * This class handles the list of currently loaded mods. + * The order matters since the order in which files are loaded matters. * */ class CModManager @@ -49,7 +50,7 @@ public: CModManager(CApplication* app, CPathManager* pathManager); //! Finds all the mods along with their metadata - void ReinitMods(); + void FindMods(); //! Removes a mod from the list of loaded mods void EnableMod(const std::string& modName); @@ -58,7 +59,13 @@ public: void DisableMod(const std::string& modName); //! Reloads application resources so the enabled mods are applied - void ReloadMods(); + void ReloadResources(); + + //! Saves the current configuration of mods to the config file + void SaveMods(); + + //! Updates the paths in Path Manager according to the current mod configuration + void UpdatePaths(); boost::optional GetMod(const std::string& modName); const std::vector& GetMods() const; diff --git a/src/app/pathman.cpp b/src/app/pathman.cpp index 4c4a1a71..080c9b70 100644 --- a/src/app/pathman.cpp +++ b/src/app/pathman.cpp @@ -73,17 +73,30 @@ void CPathManager::AddMod(const std::string &modPath) { GetLogger()->Info("Loading mod: '%s'\n", modPath.c_str()); CResourceManager::AddLocation(modPath, true); + m_mods.push_back(modPath); } void CPathManager::RemoveMod(const std::string &modPath) { GetLogger()->Info("Unloading mod: '%s'\n", modPath.c_str()); CResourceManager::RemoveLocation(modPath); + auto it = std::find(m_mods.cbegin(), m_mods.cend(), modPath); + if (it != m_mods.cend()) + m_mods.erase(it); +} + +void CPathManager::RemoveAllMods() +{ + for (const auto& modPath : m_mods) + { + CResourceManager::RemoveLocation(modPath); + } + m_mods.clear(); } bool CPathManager::ModLoaded(const std::string& modPath) { - return CResourceManager::LocationExists(modPath); + return std::find(m_mods.cbegin(), m_mods.cend(), modPath) != m_mods.end(); } std::vector CPathManager::FindMods() const diff --git a/src/app/pathman.h b/src/app/pathman.h index 7726786d..2fedfee6 100644 --- a/src/app/pathman.h +++ b/src/app/pathman.h @@ -40,6 +40,7 @@ public: void AddModSearchDir(const std::string &modSearchDirPath); void AddMod(const std::string &modPath); void RemoveMod(const std::string &modPath); + void RemoveAllMods(); bool ModLoaded(const std::string& modPath); std::vector FindMods() const; @@ -65,4 +66,6 @@ private: std::string m_savePath; //! Mod search paths std::vector m_modSearchDirs; + //! Mod paths + std::vector m_mods; }; diff --git a/src/ui/screen/screen_setup_mods.cpp b/src/ui/screen/screen_setup_mods.cpp index 6fae8151..69cd13fe 100644 --- a/src/ui/screen/screen_setup_mods.cpp +++ b/src/ui/screen/screen_setup_mods.cpp @@ -71,6 +71,8 @@ void CScreenSetupMods::CreateInterface() Math::Point pos, ddim; std::string name; + m_modManager->FindMods(); + CScreenSetup::CreateInterface(); pw = static_cast(m_interface->SearchControl(EVENT_WINDOW5)); if ( pw == nullptr ) return; @@ -155,7 +157,9 @@ bool CScreenSetupMods::EventProcess(const Event &event) modName = pl->GetItemName(pl->GetSelect()); m_modManager->EnableMod(modName); - m_modManager->ReloadMods(); + m_modManager->SaveMods(); + m_modManager->UpdatePaths(); + m_modManager->ReloadResources(); m_main->ChangePhase(PHASE_SETUPm); break; @@ -166,7 +170,9 @@ bool CScreenSetupMods::EventProcess(const Event &event) modName = pl->GetItemName(pl->GetSelect()); m_modManager->DisableMod(modName); - m_modManager->ReloadMods(); + m_modManager->SaveMods(); + m_modManager->UpdatePaths(); + m_modManager->ReloadResources(); m_main->ChangePhase(PHASE_SETUPm); break; From 56a8c5eb4862acbb1cb0cec6e48f98a7ca1a6ea9 Mon Sep 17 00:00:00 2001 From: MrSimbax Date: Sun, 19 Jul 2020 15:16:39 +0200 Subject: [PATCH 30/98] Fix build error on GCC --- src/app/modman.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/modman.cpp b/src/app/modman.cpp index ef044a8a..e2fb3468 100644 --- a/src/app/modman.cpp +++ b/src/app/modman.cpp @@ -54,7 +54,7 @@ void CModManager::FindMods() // Transform the data into Mod structures m_mods.reserve(savedModNames.size()); - for (int i = 0; i < savedModNames.size(); ++i) + for (size_t i = 0; i < savedModNames.size(); ++i) { Mod mod{}; mod.name = savedModNames[i]; From 7e6782a1beafb55b8226e397072494cd6ee8b685 Mon Sep 17 00:00:00 2001 From: MrSimbax Date: Sun, 19 Jul 2020 16:07:27 +0200 Subject: [PATCH 31/98] Try to improve font reloading --- src/graphics/engine/engine.cpp | 1 + src/graphics/engine/text.cpp | 34 ++++++++++++++++++++++++++-------- src/graphics/engine/text.h | 2 ++ 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/src/graphics/engine/engine.cpp b/src/graphics/engine/engine.cpp index 198e230d..c146d767 100644 --- a/src/graphics/engine/engine.cpp +++ b/src/graphics/engine/engine.cpp @@ -408,6 +408,7 @@ void CEngine::ReloadAllTextures() { FlushTextureCache(); m_text->FlushCache(); + m_text->ReloadFonts(); m_app->GetEventQueue()->AddEvent(Event(EVENT_RELOAD_TEXTURES)); UpdateGroundSpotTextures(); diff --git a/src/graphics/engine/text.cpp b/src/graphics/engine/text.cpp index a85bd5fd..bf8ac426 100644 --- a/src/graphics/engine/text.cpp +++ b/src/graphics/engine/text.cpp @@ -191,17 +191,32 @@ CText::~CText() bool CText::Create() { - CFontLoader fontLoader; - if (!fontLoader.Init()) - { - GetLogger()->Warn("Error on parsing fonts config file: failed to open file\n"); - } if (TTF_Init() != 0) { m_error = std::string("TTF_Init error: ") + std::string(TTF_GetError()); return false; } + if (!ReloadFonts()) + { + return false; + } + + return true; +} + +bool CText::ReloadFonts() +{ + CFontLoader fontLoader; + if (!fontLoader.Init()) + { + GetLogger()->Warn("Error on parsing fonts config file: failed to open file\n"); + } + + // Backup previous fonts + auto fonts = std::move(m_fonts); + m_fonts.clear(); + for (auto type : {FONT_COMMON, FONT_STUDIO, FONT_SATCOM}) { m_fonts[static_cast(type)] = MakeUnique(fontLoader.GetFont(type)); @@ -214,7 +229,10 @@ bool CText::Create() FontType type = (*it).first; CachedFont* cf = GetOrOpenFont(type, m_defaultSize); if (cf == nullptr || cf->font == nullptr) + { + m_fonts = std::move(fonts); return false; + } } return true; @@ -259,9 +277,9 @@ void CText::FlushCache() } } - //TODO: fix this - Destroy(); - Create(); + m_lastCachedFont = nullptr; + m_lastFontType = FONT_COMMON; + m_lastFontSize = 0; } int CText::GetTabSize() diff --git a/src/graphics/engine/text.h b/src/graphics/engine/text.h index 3a5bff88..34a2d832 100644 --- a/src/graphics/engine/text.h +++ b/src/graphics/engine/text.h @@ -256,6 +256,8 @@ public: //! Flushes cached textures void FlushCache(); + //! Try to load new font files + bool ReloadFonts(); //@{ //! Tab size management From 754dfefefdfff876022c22ae031c955cdfb55fbc Mon Sep 17 00:00:00 2001 From: Fiftytwo Date: Mon, 20 Jul 2020 18:35:31 +0200 Subject: [PATCH 32/98] Add Missions+ gamemode --- po/colobot.pot | 15 ++++++ src/common/event.cpp | 5 ++ src/common/event.h | 5 ++ src/common/restext.cpp | 6 +++ src/common/restext.h | 1 + src/level/level_category.cpp | 1 + src/level/level_category.h | 1 + src/level/robotmain.cpp | 17 +++++++ src/level/robotmain.h | 2 + src/object/motion/motionhuman.cpp | 2 +- src/object/old_object.cpp | 5 ++ src/object/old_object.h | 1 + src/object/subclass/base_building.cpp | 2 +- src/object/subclass/base_robot.cpp | 2 +- src/object/subclass/shielder.cpp | 2 +- src/ui/maindialog.cpp | 1 + src/ui/mainui.cpp | 15 ++++++ src/ui/mainui.h | 3 ++ src/ui/object_interface.cpp | 7 +-- src/ui/screen/screen_level_list.cpp | 73 ++++++++++++++++++++++++++- src/ui/screen/screen_level_list.h | 6 +++ src/ui/screen/screen_main_menu.cpp | 17 ++++++- 22 files changed, 178 insertions(+), 11 deletions(-) diff --git a/po/colobot.pot b/po/colobot.pot index a331ffba..9803a978 100644 --- a/po/colobot.pot +++ b/po/colobot.pot @@ -84,6 +84,9 @@ msgstr "" msgid "Load a saved mission" msgstr "" +msgid "Missions+" +msgstr "" + msgid "Chapters:" msgstr "" @@ -340,6 +343,9 @@ msgstr "" msgid "<< Back \\Back to the previous screen" msgstr "" +msgid "+\\Missions with bonus content and optional challenges" +msgstr "" + msgid "Play\\Start mission!" msgstr "" @@ -583,6 +589,15 @@ msgstr "" msgid "Invert\\Invert values on this axis" msgstr "" +msgid "Space Programmer\\Disables radio-control" +msgstr "" + +msgid "Space Researcher\\Disables using all previously researched technologies" +msgstr "" + +msgid "Space Explorer\\Disables astronaut abilities" +msgstr "" + msgid "\\New player name" msgstr "" diff --git a/src/common/event.cpp b/src/common/event.cpp index 214fd20e..f03830f3 100644 --- a/src/common/event.cpp +++ b/src/common/event.cpp @@ -190,6 +190,7 @@ void InitializeEventTypeTexts() EVENT_TYPE_TEXT[EVENT_INTERFACE_ABORT] = "EVENT_INTERFACE_ABORT"; EVENT_TYPE_TEXT[EVENT_INTERFACE_USER] = "EVENT_INTERFACE_USER"; EVENT_TYPE_TEXT[EVENT_INTERFACE_SATCOM] = "EVENT_INTERFACE_SATCOM"; + EVENT_TYPE_TEXT[EVENT_INTERFACE_PLUS] = "EVENT_INTERFACE_PLUS"; EVENT_TYPE_TEXT[EVENT_INTERFACE_CHAP] = "EVENT_INTERFACE_CHAP"; EVENT_TYPE_TEXT[EVENT_INTERFACE_LIST] = "EVENT_INTERFACE_LIST"; @@ -272,6 +273,10 @@ void InitializeEventTypeTexts() EVENT_TYPE_TEXT[EVENT_INTERFACE_JOYSTICK_CAM_Y_INVERT]= "EVENT_INTERFACE_JOYSTICK_CAM_Y_INVERT"; EVENT_TYPE_TEXT[EVENT_INTERFACE_JOYSTICK_CAM_Z_INVERT]= "EVENT_INTERFACE_JOYSTICK_CAM_Z_INVERT"; + EVENT_TYPE_TEXT[EVENT_INTERFACE_PLUS_TRAINER] = "EVENT_INTERFACE_PLUS_TRAINER"; + EVENT_TYPE_TEXT[EVENT_INTERFACE_PLUS_RESEARCH] = "EVENT_INTERFACE_PLUS_RESEARCH"; + EVENT_TYPE_TEXT[EVENT_INTERFACE_PLUS_EXPLORER] = "EVENT_INTERFACE_PLUS_EXPLORER"; + EVENT_TYPE_TEXT[EVENT_INTERFACE_GLINTl] = "EVENT_INTERFACE_GLINTl"; EVENT_TYPE_TEXT[EVENT_INTERFACE_GLINTr] = "EVENT_INTERFACE_GLINTr"; EVENT_TYPE_TEXT[EVENT_INTERFACE_GLINTu] = "EVENT_INTERFACE_GLINTu"; diff --git a/src/common/event.h b/src/common/event.h index c2029e82..9eace389 100644 --- a/src/common/event.h +++ b/src/common/event.h @@ -225,6 +225,7 @@ enum EventType EVENT_INTERFACE_ABORT = 412, EVENT_INTERFACE_USER = 413, EVENT_INTERFACE_SATCOM = 414, + EVENT_INTERFACE_PLUS = 415, EVENT_INTERFACE_CHAP = 420, EVENT_INTERFACE_LIST = 421, @@ -311,6 +312,10 @@ enum EventType EVENT_INTERFACE_JOYSTICK_CAM_Y_INVERT = 573, EVENT_INTERFACE_JOYSTICK_CAM_Z_INVERT = 574, + EVENT_INTERFACE_PLUS_TRAINER = 575, + EVENT_INTERFACE_PLUS_RESEARCH = 576, + EVENT_INTERFACE_PLUS_EXPLORER = 577, + EVENT_INTERFACE_GLINTl = 590, EVENT_INTERFACE_GLINTr = 591, EVENT_INTERFACE_GLINTu = 592, diff --git a/src/common/restext.cpp b/src/common/restext.cpp index cd05d59f..36cebc45 100644 --- a/src/common/restext.cpp +++ b/src/common/restext.cpp @@ -77,6 +77,7 @@ void InitializeRestext() stringsText[RT_TITLE_PERSO] = TR("Customize your appearance"); stringsText[RT_TITLE_WRITE] = TR("Save the current mission"); stringsText[RT_TITLE_READ] = TR("Load a saved mission"); + stringsText[RT_TITLE_PLUS] = TR("Missions+"); stringsText[RT_PLAY_CHAP_CHAPTERS] = TR("Chapters:"); stringsText[RT_PLAY_CHAP_PLANETS] = TR("Planets:"); @@ -181,6 +182,7 @@ void InitializeRestext() stringsEvent[EVENT_INTERFACE_ABORT] = TR("\\Return to Colobot: Gold Edition"); stringsEvent[EVENT_INTERFACE_QUIT] = TR("Quit\\Quit Colobot: Gold Edition"); stringsEvent[EVENT_INTERFACE_BACK] = TR("<< Back \\Back to the previous screen"); + stringsEvent[EVENT_INTERFACE_PLUS] = TR("+\\Missions with bonus content and optional challenges"); stringsEvent[EVENT_INTERFACE_PLAY] = TR("Play\\Start mission!"); stringsEvent[EVENT_INTERFACE_SETUPd] = TR("Device\\Driver and resolution settings"); stringsEvent[EVENT_INTERFACE_SETUPg] = TR("Graphics\\Graphics settings"); @@ -275,6 +277,10 @@ void InitializeRestext() stringsEvent[EVENT_INTERFACE_JOYSTICK_CAM_Y_INVERT] = TR("Invert\\Invert values on this axis"); stringsEvent[EVENT_INTERFACE_JOYSTICK_CAM_Z_INVERT] = TR("Invert\\Invert values on this axis"); + stringsEvent[EVENT_INTERFACE_PLUS_TRAINER] = TR("Space Programmer\\Disables radio-control"); + stringsEvent[EVENT_INTERFACE_PLUS_RESEARCH] = TR("Space Researcher\\Disables using all previously researched technologies"); + stringsEvent[EVENT_INTERFACE_PLUS_EXPLORER] = TR("Space Explorer\\Disables astronaut abilities"); + stringsEvent[EVENT_INTERFACE_NEDIT] = TR("\\New player name"); stringsEvent[EVENT_INTERFACE_NOK] = TR("OK\\Choose the selected player"); stringsEvent[EVENT_INTERFACE_NDELETE] = TR("Delete player\\Deletes the player from the list"); diff --git a/src/common/restext.h b/src/common/restext.h index c33a864f..602b3b9c 100644 --- a/src/common/restext.h +++ b/src/common/restext.h @@ -71,6 +71,7 @@ enum ResTextType RT_TITLE_WRITE = 50, RT_TITLE_READ = 51, RT_TITLE_USER = 52, + RT_TITLE_PLUS = 53, RT_PLAY_CHAP_CHAPTERS = 60, RT_PLAY_CHAP_PLANETS = 61, diff --git a/src/level/level_category.cpp b/src/level/level_category.cpp index 95c17526..e34925a3 100644 --- a/src/level/level_category.cpp +++ b/src/level/level_category.cpp @@ -29,6 +29,7 @@ const std::map CATEGORY_DIR_MAP = { { LevelCategory::Exercises, "exercises" }, { LevelCategory::Challenges, "challenges" }, { LevelCategory::CodeBattles, "battles" }, + { LevelCategory::GamePlus, "plus" }, { LevelCategory::CustomLevels, "custom" }, }; diff --git a/src/level/level_category.h b/src/level/level_category.h index 9d960c1b..39920914 100644 --- a/src/level/level_category.h +++ b/src/level/level_category.h @@ -28,6 +28,7 @@ enum class LevelCategory Missions, FreeGame, CodeBattles, + GamePlus, CustomLevels, Max, }; diff --git a/src/level/robotmain.cpp b/src/level/robotmain.cpp index 1a51c7e1..523f69c6 100644 --- a/src/level/robotmain.cpp +++ b/src/level/robotmain.cpp @@ -2461,6 +2461,7 @@ bool CRobotMain::EventFrame(const Event &event) { if (m_levelCategory == LevelCategory::Missions || m_levelCategory == LevelCategory::FreeGame || + m_levelCategory == LevelCategory::GamePlus || m_levelCategory == LevelCategory::CustomLevels) { if (!IOIsBusy() && m_missionType != MISSION_CODE_BATTLE) @@ -3781,6 +3782,12 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) m_build |= BUILD_FLAG; } + if (m_levelCategory == LevelCategory::GamePlus && !m_ui->GetPlusResearch() && !resetObject) // new game plus? + { + m_researchDone[0] |= m_playerProfile->GetFreeGameResearchUnlock(); + m_build |= m_playerProfile->GetFreeGameBuildUnlock(); + } + if (!resetObject) { m_short->SetMode(false); // vehicles? @@ -5347,6 +5354,16 @@ bool CRobotMain::GetTrainerPilot() return m_cheatTrainerPilot; } +bool CRobotMain::GetPlusTrainer() +{ + return m_ui->GetPlusTrainer(); +} + +bool CRobotMain::GetPlusExplorer() +{ + return m_ui->GetPlusExplorer(); +} + //! Indicates whether the scene is fixed, without interaction bool CRobotMain::GetFixScene() { diff --git a/src/level/robotmain.h b/src/level/robotmain.h index e95d6671..df4cbc8f 100644 --- a/src/level/robotmain.h +++ b/src/level/robotmain.h @@ -266,6 +266,8 @@ public: const std::string& GetScriptName(); const std::string& GetScriptFile(); bool GetTrainerPilot(); + bool GetPlusTrainer(); + bool GetPlusExplorer(); bool GetFixScene(); bool GetShowSoluce(); bool GetSceneSoluce(); diff --git a/src/object/motion/motionhuman.cpp b/src/object/motion/motionhuman.cpp index d6f41144..aef056c6 100644 --- a/src/object/motion/motionhuman.cpp +++ b/src/object/motion/motionhuman.cpp @@ -314,7 +314,7 @@ void CMotionHuman::Create(Math::Vector pos, float angle, ObjectType type, m_object->SetPartRotation(13, Math::Vector(10.0f*Math::PI/180.0f, -5.0f*Math::PI/180.0f, 5.0f*Math::PI/180.0f)); // Creates the neutron gun. - if ( option != 2 ) // with backpack? + if ( option != 2 && !m_main->GetPlusExplorer()) // with backpack? { rank = m_engine->CreateObject(); m_engine->SetObjectType(rank, Gfx::ENG_OBJTYPE_DESCENDANT); diff --git a/src/object/old_object.cpp b/src/object/old_object.cpp index 5fd93df8..9de9ed44 100644 --- a/src/object/old_object.cpp +++ b/src/object/old_object.cpp @@ -1627,6 +1627,11 @@ bool COldObject::GetTrainer() return m_bTrainer; } +bool COldObject::GetPlusTrainer() +{ + return m_main->GetPlusTrainer(); +} + void COldObject::SetToy(bool bEnable) { m_bToy = bEnable; diff --git a/src/object/old_object.h b/src/object/old_object.h index 9a3799be..cbb25684 100644 --- a/src/object/old_object.h +++ b/src/object/old_object.h @@ -165,6 +165,7 @@ public: void SetTrainer(bool bEnable) override; bool GetTrainer() override; + bool GetPlusTrainer(); void SetToy(bool bEnable); bool GetToy(); diff --git a/src/object/subclass/base_building.cpp b/src/object/subclass/base_building.cpp index 70ce6c73..e60c2381 100644 --- a/src/object/subclass/base_building.cpp +++ b/src/object/subclass/base_building.cpp @@ -64,7 +64,7 @@ std::unique_ptr CBaseBuilding::Create( { auto obj = MakeUnique(params.id, params.type); - obj->SetTrainer(params.trainer); + obj->SetTrainer(params.trainer || obj->GetPlusTrainer()); obj->SetTeam(params.team); float height = params.height; diff --git a/src/object/subclass/base_robot.cpp b/src/object/subclass/base_robot.cpp index 253c6fa8..3f5a21f6 100644 --- a/src/object/subclass/base_robot.cpp +++ b/src/object/subclass/base_robot.cpp @@ -65,7 +65,7 @@ std::unique_ptr CBaseRobot::Create( } else { - obj->SetTrainer(params.trainer); + obj->SetTrainer(params.trainer || obj->GetPlusTrainer()); } obj->SetToy(params.toy); diff --git a/src/object/subclass/shielder.cpp b/src/object/subclass/shielder.cpp index 80438b4d..e52b8779 100644 --- a/src/object/subclass/shielder.cpp +++ b/src/object/subclass/shielder.cpp @@ -52,7 +52,7 @@ std::unique_ptr CShielder::Create( auto obj = MakeUnique(params.id); obj->SetTeam(params.team); - obj->SetTrainer(params.trainer); + obj->SetTrainer(params.trainer || obj->GetPlusTrainer()); obj->SetToy(params.toy); auto physics = MakeUnique(obj.get()); diff --git a/src/ui/maindialog.cpp b/src/ui/maindialog.cpp index 5cdfdd47..9321619f 100644 --- a/src/ui/maindialog.cpp +++ b/src/ui/maindialog.cpp @@ -201,6 +201,7 @@ void CMainDialog::StartPauseMenu() if ( (m_main->GetLevelCategory() == LevelCategory::Missions || // missions ? m_main->GetLevelCategory() == LevelCategory::FreeGame || // free games? + m_main->GetLevelCategory() == LevelCategory::GamePlus || // new game plus? m_main->GetLevelCategory() == LevelCategory::CustomLevels ) && // user ? m_main->GetMissionType() != MISSION_CODE_BATTLE ) { diff --git a/src/ui/mainui.cpp b/src/ui/mainui.cpp index 4070e5ec..a7cbab61 100644 --- a/src/ui/mainui.cpp +++ b/src/ui/mainui.cpp @@ -762,6 +762,21 @@ bool CMainUserInterface::GetSceneSoluce() return m_screenLevelList->GetSceneSoluce(); } +bool CMainUserInterface::GetPlusTrainer() +{ + return m_screenLevelList->GetPlusTrainer(); +} + +bool CMainUserInterface::GetPlusResearch() +{ + return m_screenLevelList->GetPlusResearch(); +} + +bool CMainUserInterface::GetPlusExplorer() +{ + return m_screenLevelList->GetPlusExplorer(); +} + bool CMainUserInterface::GetGamerOnlyHead() { if (m_phase == PHASE_APPERANCE) diff --git a/src/ui/mainui.h b/src/ui/mainui.h index 50888f5b..c1f46e79 100644 --- a/src/ui/mainui.h +++ b/src/ui/mainui.h @@ -76,6 +76,9 @@ public: void ChangePhase(Phase phase); bool GetSceneSoluce(); + bool GetPlusTrainer(); + bool GetPlusResearch(); + bool GetPlusExplorer(); void UpdateChapterPassed(); void NextMission(); diff --git a/src/ui/object_interface.cpp b/src/ui/object_interface.cpp index 834523e5..abee9b2b 100644 --- a/src/ui/object_interface.cpp +++ b/src/ui/object_interface.cpp @@ -943,8 +943,9 @@ bool CObjectInterface::CreateInterface(bool bSelect) } } - if ( type == OBJECT_HUMAN || - type == OBJECT_TECH ) + if ( (type == OBJECT_HUMAN || + type == OBJECT_TECH ) && + !m_main->GetPlusExplorer() ) { pos.x = ox+sx*7.7f; pos.y = oy+sy*0.5f; @@ -986,7 +987,7 @@ bool CObjectInterface::CreateInterface(bool bSelect) DefaultEnter(pw, EVENT_OBJECT_MTAKE); } - if ( type == OBJECT_HUMAN ) // builder? + if ( type == OBJECT_HUMAN && !m_main->GetPlusExplorer()) // builder? { pos.x = 1.0f/640.0f; pos.y = 4.0f/480.0f; diff --git a/src/ui/screen/screen_level_list.cpp b/src/ui/screen/screen_level_list.cpp index 2ae5e29d..b0ed6460 100644 --- a/src/ui/screen/screen_level_list.cpp +++ b/src/ui/screen/screen_level_list.cpp @@ -48,6 +48,9 @@ CScreenLevelList::CScreenLevelList(CMainDialog* mainDialog) : m_dialog(mainDialog), m_category{}, m_sceneSoluce{false}, + m_plusTrainer{false}, + m_plusResearch{false}, + m_plusExplorer{false}, m_maxList{0}, m_accessChap{0} { @@ -86,6 +89,7 @@ void CScreenLevelList::CreateInterface() if ( m_category == LevelCategory::Missions ) res = RT_TITLE_MISSION; if ( m_category == LevelCategory::FreeGame ) res = RT_TITLE_FREE; if ( m_category == LevelCategory::CodeBattles ) res = RT_TITLE_CODE_BATTLES; + if ( m_category == LevelCategory::GamePlus ) res = RT_TITLE_PLUS; if ( m_category == LevelCategory::CustomLevels ) res = RT_TITLE_USER; GetResource(RES_TEXT, res, name); pw->SetName(name); @@ -109,6 +113,7 @@ void CScreenLevelList::CreateInterface() res = RT_PLAY_CHAP_CHAPTERS; if ( m_category == LevelCategory::Missions ) res = RT_PLAY_CHAP_PLANETS; if ( m_category == LevelCategory::FreeGame ) res = RT_PLAY_CHAP_PLANETS; + if ( m_category == LevelCategory::GamePlus ) res = RT_PLAY_CHAP_PLANETS; if ( m_category == LevelCategory::CustomLevels ) res = RT_PLAY_CHAP_USERLVL; GetResource(RES_TEXT, res, name); pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL11, name); @@ -138,6 +143,7 @@ void CScreenLevelList::CreateInterface() if ( m_category == LevelCategory::Challenges ) res = RT_PLAY_LIST_CHALLENGES; if ( m_category == LevelCategory::Missions ) res = RT_PLAY_LIST_MISSIONS; if ( m_category == LevelCategory::FreeGame ) res = RT_PLAY_LIST_FREEGAME; + if ( m_category == LevelCategory::GamePlus ) res = RT_PLAY_LIST_MISSIONS; GetResource(RES_TEXT, res, name); pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL12, name); pl->SetTextAlign(Gfx::TEXT_ALIGN_LEFT); @@ -179,6 +185,7 @@ void CScreenLevelList::CreateInterface() // Button displays the "soluce": if ( m_category != LevelCategory::Exercises && + m_category != LevelCategory::GamePlus && m_category != LevelCategory::FreeGame ) { pos.x = ox+sx*9.5f; @@ -191,10 +198,36 @@ void CScreenLevelList::CreateInterface() } m_sceneSoluce = false; + if ( m_category == LevelCategory::GamePlus ) + { + pos.x = ox+sx*9.5f; + pos.y = oy+sy*6.1f; + ddim.x = dim.x*3.4f; + ddim.y = dim.y*0.5f; + pc = pw->CreateCheck(pos, ddim, -1, EVENT_INTERFACE_PLUS_TRAINER); + pc->SetState(STATE_SHADOW); + pc->ClearState(STATE_CHECK); + + pos.y = oy+sy*5.5f; + pc = pw->CreateCheck(pos, ddim, -1, EVENT_INTERFACE_PLUS_RESEARCH); + pc->SetState(STATE_SHADOW); + pc->ClearState(STATE_CHECK); + + pos.x = ox+sx*12.9f; + pos.y = oy+sy*6.1f; + pc = pw->CreateCheck(pos, ddim, -1, EVENT_INTERFACE_PLUS_EXPLORER); + pc->SetState(STATE_SHADOW); + pc->ClearState(STATE_CHECK); + } + m_plusTrainer = false; + m_plusResearch = false; + m_plusExplorer = false; + UpdateSceneResume(m_chap[m_category]+1, m_sel[m_category]+1); if ( m_category == LevelCategory::Missions || m_category == LevelCategory::FreeGame || + m_category == LevelCategory::GamePlus || m_category == LevelCategory::CustomLevels ) { pos.x = ox+sx*9.5f; @@ -295,6 +328,27 @@ bool CScreenLevelList::EventProcess(const Event &event) pb->SetState(STATE_CHECK, m_sceneSoluce); break; + case EVENT_INTERFACE_PLUS_TRAINER: + pb = static_cast(pw->SearchControl(EVENT_INTERFACE_PLUS_TRAINER)); + if ( pb == nullptr ) break; + m_plusTrainer = !m_plusTrainer; + pb->SetState(STATE_CHECK, m_plusTrainer); + break; + + case EVENT_INTERFACE_PLUS_RESEARCH: + pb = static_cast(pw->SearchControl(EVENT_INTERFACE_PLUS_RESEARCH)); + if ( pb == nullptr ) break; + m_plusResearch = !m_plusResearch; + pb->SetState(STATE_CHECK, m_plusResearch); + break; + + case EVENT_INTERFACE_PLUS_EXPLORER: + pb = static_cast(pw->SearchControl(EVENT_INTERFACE_PLUS_EXPLORER)); + if ( pb == nullptr ) break; + m_plusExplorer = !m_plusExplorer; + pb->SetState(STATE_CHECK, m_plusExplorer); + break; + case EVENT_INTERFACE_PLAY: m_main->SetLevel(m_category, m_chap[m_category]+1, m_sel[m_category]+1); m_main->ChangePhase(PHASE_SIMUL); @@ -331,6 +385,21 @@ bool CScreenLevelList::GetSceneSoluce() return m_sceneSoluce; } +bool CScreenLevelList::GetPlusTrainer() +{ + return m_plusTrainer; +} + +bool CScreenLevelList::GetPlusResearch() +{ + return m_plusResearch; +} + +bool CScreenLevelList::GetPlusExplorer() +{ + return m_plusExplorer; +} + // Updates the chapters of exercises or missions. void CScreenLevelList::UpdateSceneChap(int &chap) @@ -392,7 +461,7 @@ void CScreenLevelList::UpdateSceneChap(int &chap) pl->SetCheck(j, bPassed); pl->SetEnable(j, true); - if ( m_category == LevelCategory::Missions && !m_main->GetShowAll() && !bPassed ) + if ( (m_category == LevelCategory::Missions || m_category == LevelCategory::GamePlus) && !m_main->GetShowAll() && !bPassed ) { j ++; break; @@ -459,7 +528,7 @@ void CScreenLevelList::UpdateSceneList(int chap, int &sel) pl->SetCheck(j, bPassed); pl->SetEnable(j, true); - if ( m_category == LevelCategory::Missions && !m_main->GetShowAll() && !bPassed ) + if ( (m_category == LevelCategory::Missions || m_category == LevelCategory::GamePlus) && !m_main->GetShowAll() && !bPassed ) { readAll = false; } diff --git a/src/ui/screen/screen_level_list.h b/src/ui/screen/screen_level_list.h index 09eef79a..089dc558 100644 --- a/src/ui/screen/screen_level_list.h +++ b/src/ui/screen/screen_level_list.h @@ -43,6 +43,9 @@ public: void SetSelection(LevelCategory category, int chap, int rank); bool GetSceneSoluce(); + bool GetPlusTrainer(); + bool GetPlusResearch(); + bool GetPlusExplorer(); void AllMissionUpdate(); void ShowSoluceUpdate(); @@ -65,6 +68,9 @@ protected: LevelCategory m_category; bool m_sceneSoluce; + bool m_plusTrainer; + bool m_plusResearch; + bool m_plusExplorer; std::map m_chap; // selected chapter (0..8) std::map m_sel; // chosen mission (0..98) diff --git a/src/ui/screen/screen_main_menu.cpp b/src/ui/screen/screen_main_menu.cpp index 2d69ae1c..ccabdfc1 100644 --- a/src/ui/screen/screen_main_menu.cpp +++ b/src/ui/screen/screen_main_menu.cpp @@ -91,14 +91,22 @@ void CScreenMainMenu::CreateInterface() pg = pw->CreateGroup(pos, ddim, 26, EVENT_LABEL1); // quit pg->SetState(STATE_SHADOW); - ddim.x = 0.18f; + ddim.x = 0.12f; ddim.y = dim.y*0.8f; pos.x = 0.41f; - pos.y = oy+sy*10.5f; + pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_MISSION); pb->SetState(STATE_SHADOW); + ddim.x = 0.06f; + pos.x = 0.53f; + pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_PLUS); + pb->SetState(STATE_SHADOW); + + ddim.x = 0.18f; + pos.x = 0.41f; + pos.y = oy+sy*9.6f; pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_FREE); pb->SetState(STATE_SHADOW); @@ -218,6 +226,11 @@ bool CScreenMainMenu::EventProcess(const Event &event) m_main->ChangePhase(PHASE_LEVEL_LIST); break; + case EVENT_INTERFACE_PLUS: + m_main->SetLevel(LevelCategory::GamePlus, 0, 0); + m_main->ChangePhase(PHASE_LEVEL_LIST); + break; + case EVENT_INTERFACE_USER: m_main->SetLevel(LevelCategory::CustomLevels, 0, 0); m_main->ChangePhase(PHASE_LEVEL_LIST); From dc6cfbb691d5ac1b192c78d165b25acd9663f764 Mon Sep 17 00:00:00 2001 From: krzys_h Date: Mon, 20 Jul 2020 19:34:44 +0200 Subject: [PATCH 33/98] Use colobot-lint from GitHub Actions rather than Jenkins --- .github/workflows/lint.yml | 58 +++++++++++++++++++++++++++++++++----- 1 file changed, 51 insertions(+), 7 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 7fd67c4a..93d109bf 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -13,16 +13,61 @@ jobs: steps: - name: Download Colobot dependencies run: sudo apt-get update && sudo apt-get install -y --no-install-recommends build-essential cmake libsdl2-dev libsdl2-image-dev libsdl2-ttf-dev libsndfile1-dev libvorbis-dev libogg-dev libpng-dev libglew-dev libopenal-dev libboost-dev libboost-system-dev libboost-filesystem-dev libboost-regex-dev libphysfs-dev gettext git po4a vorbis-tools librsvg2-bin xmlstarlet - # TODO: migrate colobot-lint to GitHub Actions + - name: Download colobot-lint dependencies + run: sudo apt-get install -y --no-install-recommends clang-3.6 libtinyxml2.6.2v5 + - run: pip install requests + - run: mkdir -p /tmp/colobot-lint - name: Download colobot-lint + working-directory: /tmp/colobot-lint + shell: python + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + REPO_NAME: colobot/colobot-lint + BRANCH_NAME: master + ARTIFACT_NAME: colobot-lint run: | - sudo apt-get install -y --no-install-recommends clang-3.6 libtinyxml2.6.2v5 - mkdir -p /tmp/colobot-lint - cd /tmp/colobot-lint - wget -O colobot-lint.zip "https://compiled.colobot.info/job/colobot/job/colobot-lint/job/dev/lastSuccessfulBuild/artifact/*zip*/archive.zip" + import os + import requests + # How there can be no builtin action to download the latest artifact from another repo?! + + s = requests.Session() + s.headers.update({ + 'Authorization': 'token ' + os.environ['GITHUB_TOKEN'], + 'Accept': 'application/vnd.github.v3+json' + }) + + r = s.get("https://api.github.com/repos/" + os.environ['REPO_NAME'] + "/actions/runs", params={'branch': os.environ['BRANCH_NAME'], 'event': 'push', 'status': 'success'}) + r.raise_for_status() + + # Querying for "dev" returns all branches that have "dev" anywhere in the name... is that a GitHub bug or intended behaviour? + runs = list(filter(lambda x: x['head_branch'] == os.environ['BRANCH_NAME'], r.json()['workflow_runs'])) + if len(runs) == 0: + raise Exception('No valid run found') + run = runs[0] + print("Using colobot-lint from run #{} ({}) for commit {}".format(run['run_number'], run['id'], run['head_sha'])) + + r = s.get(run['artifacts_url']) + r.raise_for_status() + artifacts = list(filter(lambda x: x['name'] == os.environ['ARTIFACT_NAME'], r.json()['artifacts'])) + if len(artifacts) != 1: + raise Exception('Artifact not found') + artifact = artifacts[0] + print(artifact['archive_download_url']) + + r = s.get(artifact['archive_download_url'], stream=True) + r.raise_for_status() + with open(os.environ['ARTIFACT_NAME'] + '.zip', 'wb') as f: + for block in r.iter_content(1024): + f.write(block) + print("Download finished") + - name: Unpack colobot-lint + working-directory: /tmp/colobot-lint + run: | # Unzip the archive - unzip ./colobot-lint.zip + mkdir archive; cd archive + unzip ../colobot-lint.zip + cd .. # Workaround for Clang not finding system headers mkdir ./bin mv ./archive/build/colobot-lint ./bin/ @@ -73,7 +118,6 @@ jobs: with: name: HTML results path: build/html_report - - run: pip install requests - name: Send linter results to GitHub shell: python env: From b47ee4dd1e2c82589aeb284a7261d42294219ede Mon Sep 17 00:00:00 2001 From: krzys-h Date: Mon, 20 Jul 2020 20:11:02 +0200 Subject: [PATCH 34/98] Don't try to upload annotations for pull requests from forks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The GITHUB_TOKEN is readonly when running from a fork... and I've found exactly 0 workarounds for this issue I wanted to check permissions on the actual token rather than if we are running inside a fork, but the header that is supposed to specify the permissions doesn't exist under GH Actions (╯°□°)╯︵ ┻━┻ --- .github/workflows/lint.yml | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 93d109bf..c28c0da5 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -122,6 +122,7 @@ jobs: shell: python env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ACTUALLY_SEND: ${{ github.event.type != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} run: | import os import sys @@ -229,21 +230,25 @@ jobs: summary = 'colobot-lint found {} issues'.format(len(annotations)) all_ok = len(annotations) == 0 + print('Conclusion: {}'.format(summary)) - # Annotations have to be sent in batches of 50 - first = True - while first or len(annotations) > 0: - first = False - to_send = annotations[:50] - annotations = annotations[50:] - data = { - 'output': { - 'title': summary, - 'summary': summary, - 'annotations': to_send + if os.environ['ACTUALLY_SEND'] != "true": + print('Skip uploading the results as annotations because tokens from forks are readonly and there seems to be no way to do it. Blame GitHub Actions devs.') + else: + # Annotations have to be sent in batches of 50 + first = True + while first or len(annotations) > 0: + first = False + to_send = annotations[:50] + annotations = annotations[50:] + data = { + 'output': { + 'title': summary, + 'summary': summary, + 'annotations': to_send + } } - } - r = s.patch(check_run['url'], json=data) - r.raise_for_status() + r = s.patch(check_run['url'], json=data) + r.raise_for_status() sys.exit(0 if all_ok else 1) From c4385961c4d73e8548b23def377ae53c98f32f1f Mon Sep 17 00:00:00 2001 From: Droog71 <71droog71@gmail.com> Date: Mon, 20 Jul 2020 15:55:44 -0400 Subject: [PATCH 35/98] Fix for issue #1163 (#1332) * Clamped power variable before assignment to params in object manager. Attempted to fix formatting issues. * Fixed Clamp function not implemented correctly. * Fixed formatting issue, space after commas. * Created ClampPower method in object_manager.h and implemented in object_manager.cpp, Removed similar code from robotmain.cpp * Removed redundant call to ClampPower in object_manager.cpp * Added second call to ClampPower back to object_manager.cpp. Made ClampPower method private. Attempted to fix whitespace issues. * Fixed missing assignment to params.power in CreateObject method of object_manager.cpp * fixed white space at end of line 182 in object_manager.h * Fixed doxygen compatibility issue. --- src/object/object_manager.cpp | 14 +++++++++++++- src/object/object_manager.h | 2 ++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/object/object_manager.cpp b/src/object/object_manager.cpp index fd335014..bab1f3ac 100644 --- a/src/object/object_manager.cpp +++ b/src/object/object_manager.cpp @@ -142,6 +142,8 @@ CObject* CObjectManager::CreateObject(ObjectCreateParams params) } } + params.power = ClampPower(params.type,params.power); + assert(m_objects.find(params.id) == m_objects.end()); auto objectUPtr = m_objectFactory->CreateObject(params); @@ -163,10 +165,20 @@ CObject* CObjectManager::CreateObject(Math::Vector pos, float angle, ObjectType params.angle = angle; params.type = type; params.power = power; - return CreateObject(params); } +float CObjectManager::ClampPower(ObjectType type, float power) +{ + float min = 0; + float max = 100; + if (type == OBJECT_POWER || type == OBJECT_ATOMIC) + { + max = 1; + } + return Math::Clamp(power, min, max); +} + std::vector CObjectManager::GetObjectsOfTeam(int team) { std::vector result; diff --git a/src/object/object_manager.h b/src/object/object_manager.h index b5296156..3ae55c84 100644 --- a/src/object/object_manager.h +++ b/src/object/object_manager.h @@ -303,6 +303,8 @@ public: //@} private: + //! Prevents creation of overcharged power cells + float ClampPower(ObjectType type, float power); void CleanRemovedObjectsIfNeeded(); private: From 242477e3ee72bf5160d9af4907f8be0323bdd2a2 Mon Sep 17 00:00:00 2001 From: MrSimbax Date: Mon, 20 Jul 2020 22:12:51 +0200 Subject: [PATCH 36/98] Major UI change to mod manager Move the button to the sidebar. Add reordering option. General improvements and refactoring. --- CMakeLists.txt | 4 +- po/colobot.pot | 39 ++- po/cs.po | 58 +++- po/de.po | 58 +++- po/fr.po | 58 +++- po/pl.po | 58 +++- po/pt.po | 58 +++- po/ru.po | 58 +++- src/CMakeLists.txt | 4 +- src/app/modman.cpp | 61 ++-- src/app/modman.h | 35 +- src/common/event.cpp | 13 +- src/common/event.h | 18 +- src/common/restext.cpp | 23 +- src/common/restext.h | 10 +- src/level/robotmain.cpp | 7 +- src/level/robotmain.h | 3 +- src/ui/maindialog.cpp | 1 - src/ui/mainui.cpp | 16 +- src/ui/mainui.h | 4 +- src/ui/screen/screen_main_menu.cpp | 10 + src/ui/screen/screen_mod_list.cpp | 490 ++++++++++++++++++++++++++++ src/ui/screen/screen_mod_list.h | 96 ++++++ src/ui/screen/screen_setup.cpp | 23 +- src/ui/screen/screen_setup_mods.cpp | 289 ---------------- src/ui/screen/screen_setup_mods.h | 52 --- 26 files changed, 1007 insertions(+), 539 deletions(-) create mode 100644 src/ui/screen/screen_mod_list.cpp create mode 100644 src/ui/screen/screen_mod_list.h delete mode 100644 src/ui/screen/screen_setup_mods.cpp delete mode 100644 src/ui/screen/screen_setup_mods.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 63f1ace6..94c3a574 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -192,9 +192,9 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") set(DEBUG_CXX_FLAGS "/MTd /ZI") else(MSVC_STATIC) set(RELEASE_CXX_FLAGS "/MD /Ox") - set(DEBUG_CXX_FLAGS "/MDd /ZI") + set(DEBUG_CXX_FLAGS "/MDd /Od /ZI") endif() - set(TEST_CXX_FLAGS "") + set(TEST_CXX_FLAGS "${DEBUG_CXX_FLAGS}") add_definitions(-DNOEXCEPT= -DHAS_MSVC_EXCEPTION_BUG) # Needed for Debug information (it's set to "No" by default for some reason) diff --git a/po/colobot.pot b/po/colobot.pot index a6b61ea3..53bfda71 100644 --- a/po/colobot.pot +++ b/po/colobot.pot @@ -84,6 +84,9 @@ msgstr "" msgid "Load a saved mission" msgstr "" +msgid "Mods" +msgstr "" + msgid "Chapters:" msgstr "" @@ -120,10 +123,19 @@ msgstr "" msgid "2) Then press the key you want to use instead." msgstr "" -msgid "Unloaded Mods:" +msgid "Mods:" msgstr "" -msgid "Loaded Mods:" +msgid "Information:" +msgstr "" + +msgid "Description:" +msgstr "" + +msgid "Enable\\Enable the selected mod" +msgstr "" + +msgid "Disable\\Disable the selected mod" msgstr "" msgid "Face type:" @@ -186,6 +198,9 @@ msgstr "" msgid "The address %s could not be opened in a web browser." msgstr "" +msgid "There are unsaved changes. Do you want to save them before leaving?" +msgstr "" + msgid "Keyword help(\\key cbot;)" msgstr "" @@ -336,6 +351,9 @@ msgstr "" msgid "SatCom" msgstr "" +msgid "Mods\\Mod manager" +msgstr "" + msgid "Change player\\Change player" msgstr "" @@ -363,16 +381,22 @@ msgstr "" msgid "Play\\Start mission!" msgstr "" -msgid "Workshop\\Open Workshop to search Mods" +msgid "Workshop\\Open the workshop to search for mods" msgstr "" -msgid "Open Directory\\Open Mods directory" +msgid "Open Directory\\Open the mods directory" msgstr "" -msgid "Load\\Load Mod" +msgid "Apply\\Apply the current mod configuration" msgstr "" -msgid "Unload\\Unload Mod" +msgid "Up\\Move the selected mod up so it's loaded sooner (mods may overwrite files from the mods above them)" +msgstr "" + +msgid "Down\\Move the selected mod down so it's loaded later (mods may overwrite files from the mods above them)" +msgstr "" + +msgid "Refresh\\Refresh the list of currently installed mods" msgstr "" msgid "Device\\Driver and resolution settings" @@ -390,9 +414,6 @@ msgstr "" msgid "Sound\\Music and game sound volume" msgstr "" -msgid "Mods\\Manage installed mods" -msgstr "" - msgid "Unit" msgstr "" diff --git a/po/cs.po b/po/cs.po index 7fff13fe..532510ea 100644 --- a/po/cs.po +++ b/po/cs.po @@ -125,6 +125,9 @@ msgstr "Vzhled\\Upravte svůj vzhled" msgid "Apply changes\\Activates the changed settings" msgstr "Uložit změny\\Aktivovat změny nastavení" +msgid "Apply\\Apply the current mod configuration" +msgstr "" + msgid "Appropriate constructor missing" msgstr "Chybí vhodný konstruktor" @@ -479,6 +482,10 @@ msgstr "Vrtná věž" msgid "Descend\\Reduces the power of the jet" msgstr "Klesat\\Snížit tah tryskového motoru" +#, fuzzy +msgid "Description:" +msgstr "Rozlišení:" + msgid "Destroy" msgstr "Zbourat" @@ -491,6 +498,10 @@ msgstr "Drtič" msgid "Device\\Driver and resolution settings" msgstr "Obrazovka\\Nastavení grafické karty a rozlišení" +#, fuzzy +msgid "Disable\\Disable the selected mod" +msgstr "Smazat\\Smaže vybraný soubor" + msgid "Dividing by zero" msgstr "Dělení nulou" @@ -507,6 +518,9 @@ msgstr "Dveře blokuje robot nebo jiný objekt" msgid "Down (\\key gdown;)" msgstr "Dolů (\\key gdown;)" +msgid "Down\\Move the selected mod down so it's loaded later (mods may overwrite files from the mods above them)" +msgstr "" + msgid "Drawer bot" msgstr "Tužkobot" @@ -534,6 +548,10 @@ msgstr "Vejce" msgid "Empty character constant" msgstr "" +#, fuzzy +msgid "Enable\\Enable the selected mod" +msgstr "Nahrát\\Nahraje vybranou misi" + msgid "End of block missing" msgstr "Chybí konec bloku" @@ -760,6 +778,9 @@ msgstr "Infikováno virem; dočasně mimo provoz" msgid "Information exchange post" msgstr "Komunikační stanice" +msgid "Information:" +msgstr "" + msgid "Instruction \"break\" outside a loop" msgstr "Příkaz \"break\" mimo cyklus" @@ -850,18 +871,12 @@ msgstr "Seznam uložených misí" msgid "Load a saved mission" msgstr "Nahrát uloženou misi" -msgid "Load\\Load Mod" -msgstr "" - msgid "Load\\Load a saved mission" msgstr "Nahrát\\Nahrát uloženou misi" msgid "Load\\Loads the selected mission" msgstr "Nahrát\\Nahraje vybranou misi" -msgid "Loaded Mods:" -msgstr "" - msgid "Loading basic level settings" msgstr "Načítám základní nastavení mapy" @@ -916,7 +931,13 @@ msgstr "Mise na této planetě:" msgid "Missions\\Select mission" msgstr "Mise\\Vyberte misi" -msgid "Mods\\Manage installed mods" +msgid "Mods" +msgstr "" + +msgid "Mods:" +msgstr "" + +msgid "Mods\\Mod manager" msgstr "" msgid "Mouse inversion X\\Inversion of the scrolling direction on the X axis" @@ -1087,7 +1108,7 @@ msgstr "Otevřít" msgid "Open (Ctrl+O)" msgstr "Otevřít (Ctrl+O)" -msgid "Open Directory\\Open Mods directory" +msgid "Open Directory\\Open the mods directory" msgstr "" msgid "Opening brace missing" @@ -1300,6 +1321,9 @@ msgstr "Červená vlajka" msgid "Reflections on the buttons \\Shiny buttons" msgstr "Odlesky na tlačítkách\\Blyštivá tlačítka" +msgid "Refresh\\Refresh the list of currently installed mods" +msgstr "" + msgid "Remains of Apollo mission" msgstr "Pozůstatky mise Apollo" @@ -1584,6 +1608,9 @@ msgstr "" msgid "The types of the two operands are incompatible" msgstr "Operaci nelze provést s operandy těchto dvou typů" +msgid "There are unsaved changes. Do you want to save them before leaving?" +msgstr "" + msgid "This class already exists" msgstr "Tato třída již existuje" @@ -1717,15 +1744,12 @@ msgstr "Neznámá zástupná sekvence" msgid "Unknown function" msgstr "Neznámá funkce" -msgid "Unload\\Unload Mod" -msgstr "" - -msgid "Unloaded Mods:" -msgstr "" - msgid "Up (\\key gup;)" msgstr "Vzhůru (\\key gup;)" +msgid "Up\\Move the selected mod up so it's loaded sooner (mods may overwrite files from the mods above them)" +msgstr "" + msgid "Uranium deposit (site for derrick)" msgstr "Uranové ložisko (místo pro vrtnou věž)" @@ -1798,7 +1822,7 @@ msgstr "Létající detektor" msgid "Withdraw shield (\\key action;)" msgstr "Vypnout štít (\\key action;)" -msgid "Workshop\\Open Workshop to search Mods" +msgid "Workshop\\Open the workshop to search for mods" msgstr "" msgid "Worm" @@ -1956,3 +1980,7 @@ msgstr "colobot.info" msgid "epsitec.com" msgstr "epsitec.com" + +#, fuzzy +#~ msgid "No mods installed!" +#~ msgstr "Žádné uživatelské mapy nejsou nainstalovány!" diff --git a/po/de.po b/po/de.po index 702bab19..15f4c336 100644 --- a/po/de.po +++ b/po/de.po @@ -126,6 +126,9 @@ msgstr "Aussehen\\Erscheinungsbild des Astronauten einstellen" msgid "Apply changes\\Activates the changed settings" msgstr "Änderungen anwenden\\Getätigte Einstellungen anwenden" +msgid "Apply\\Apply the current mod configuration" +msgstr "" + msgid "Appropriate constructor missing" msgstr "Es gibt keinen geeigneten Konstruktor" @@ -480,6 +483,10 @@ msgstr "Bohrturm" msgid "Descend\\Reduces the power of the jet" msgstr "Sinken\\Leistung des Triebwerks drosseln" +#, fuzzy +msgid "Description:" +msgstr "Auflösung:" + msgid "Destroy" msgstr "Zerstören" @@ -492,6 +499,10 @@ msgstr "Einstampfer" msgid "Device\\Driver and resolution settings" msgstr "Bildschirm\\Driver und Bildschirmauflösung" +#, fuzzy +msgid "Disable\\Disable the selected mod" +msgstr "Löschen\\Löscht die gespeicherte Mission" + msgid "Dividing by zero" msgstr "Division durch Null" @@ -508,6 +519,9 @@ msgstr "Die Türen werden von einem Gegenstand blockiert" msgid "Down (\\key gdown;)" msgstr "Sinkt (\\key gdown;)" +msgid "Down\\Move the selected mod down so it's loaded later (mods may overwrite files from the mods above them)" +msgstr "" + msgid "Drawer bot" msgstr "Zeichner" @@ -535,6 +549,10 @@ msgstr "Ei" msgid "Empty character constant" msgstr "" +#, fuzzy +msgid "Enable\\Enable the selected mod" +msgstr "Laden\\Öffnet eine gespeicherte Mission" + msgid "End of block missing" msgstr "Es fehlt eine geschlossene geschweifte Klammer \"}\" (Ende des Blocks)" @@ -762,6 +780,9 @@ msgstr "Von Virus infiziert, zeitweise außer Betrieb" msgid "Information exchange post" msgstr "Infoserver" +msgid "Information:" +msgstr "" + msgid "Instruction \"break\" outside a loop" msgstr "Anweisung \"break\" außerhalb einer Schleife" @@ -852,18 +873,12 @@ msgstr "Liste der gespeicherten Missionen" msgid "Load a saved mission" msgstr "Gespeicherte Mission laden" -msgid "Load\\Load Mod" -msgstr "" - msgid "Load\\Load a saved mission" msgstr "Laden\\Eine gespeicherte Mission öffnen" msgid "Load\\Loads the selected mission" msgstr "Laden\\Öffnet eine gespeicherte Mission" -msgid "Loaded Mods:" -msgstr "" - msgid "Loading basic level settings" msgstr "Lade Level-Grundeinstellungen" @@ -932,7 +947,13 @@ msgstr "Liste der Missionen des Planeten:" msgid "Missions\\Select mission" msgstr "Missionen\\Aufbruch ins Weltall" -msgid "Mods\\Manage installed mods" +msgid "Mods" +msgstr "" + +msgid "Mods:" +msgstr "" + +msgid "Mods\\Mod manager" msgstr "" msgid "Mouse inversion X\\Inversion of the scrolling direction on the X axis" @@ -1103,7 +1124,7 @@ msgstr "Öffnen" msgid "Open (Ctrl+O)" msgstr "Öffnen (Ctrl+O)" -msgid "Open Directory\\Open Mods directory" +msgid "Open Directory\\Open the mods directory" msgstr "" msgid "Opening brace missing" @@ -1317,6 +1338,9 @@ msgstr "Rote Fahne" msgid "Reflections on the buttons \\Shiny buttons" msgstr "Glänzende Tasten\\Glänzende Tasten in den Menüs" +msgid "Refresh\\Refresh the list of currently installed mods" +msgstr "" + msgid "Remains of Apollo mission" msgstr "Überreste einer Apollo-Mission" @@ -1601,6 +1625,9 @@ msgstr "" msgid "The types of the two operands are incompatible" msgstr "Die zwei Operanden sind nicht kompatibel" +msgid "There are unsaved changes. Do you want to save them before leaving?" +msgstr "" + msgid "This class already exists" msgstr "Diese Klasse gibt es schon" @@ -1734,15 +1761,12 @@ msgstr "" msgid "Unknown function" msgstr "Unbekannte Funktion" -msgid "Unload\\Unload Mod" -msgstr "" - -msgid "Unloaded Mods:" -msgstr "" - msgid "Up (\\key gup;)" msgstr "Steigt (\\key gup;)" +msgid "Up\\Move the selected mod up so it's loaded sooner (mods may overwrite files from the mods above them)" +msgstr "" + msgid "Uranium deposit (site for derrick)" msgstr "Markierung für unterirdisches Platinvorkommen" @@ -1815,7 +1839,7 @@ msgstr "Schnüffler" msgid "Withdraw shield (\\key action;)" msgstr "Schutzschild einholen (\\key action;)" -msgid "Workshop\\Open Workshop to search Mods" +msgid "Workshop\\Open the workshop to search for mods" msgstr "" msgid "Worm" @@ -2051,6 +2075,10 @@ msgstr "epsitec.com" #~ msgid "Mouse shadow\\Gives the mouse a shadow" #~ msgstr "Schatten unter der Maus\\Ein Schatten erscheint unter der Maus" +#, fuzzy +#~ msgid "No mods installed!" +#~ msgstr "Keine benutzerdefinierten Level vorhanden" + #~ msgid "No other robot" #~ msgstr "Kein anderer Roboter" diff --git a/po/fr.po b/po/fr.po index dcb5d42e..1b07f1fe 100644 --- a/po/fr.po +++ b/po/fr.po @@ -125,6 +125,9 @@ msgstr "Aspect\\Choisir votre aspect" msgid "Apply changes\\Activates the changed settings" msgstr "Appliquer les changements\\Active les changements effectués" +msgid "Apply\\Apply the current mod configuration" +msgstr "" + msgid "Appropriate constructor missing" msgstr "Constructeur approprié manquant" @@ -482,6 +485,10 @@ msgstr "Derrick" msgid "Descend\\Reduces the power of the jet" msgstr "Descendre\\Diminuer la puissance du réacteur" +#, fuzzy +msgid "Description:" +msgstr "Résolutions :" + msgid "Destroy" msgstr "Détruire" @@ -494,6 +501,10 @@ msgstr "Destructeur" msgid "Device\\Driver and resolution settings" msgstr "Affichage\\Pilote et résolution d'affichage" +#, fuzzy +msgid "Disable\\Disable the selected mod" +msgstr "Supprimer\\Supprime l'enregistrement sélectionné" + msgid "Dividing by zero" msgstr "Division par zéro" @@ -510,6 +521,9 @@ msgstr "Portes bloquées par un robot ou un objet" msgid "Down (\\key gdown;)" msgstr "Descend (\\key gdown;)" +msgid "Down\\Move the selected mod down so it's loaded later (mods may overwrite files from the mods above them)" +msgstr "" + msgid "Drawer bot" msgstr "Robot dessinateur" @@ -537,6 +551,10 @@ msgstr "Oeuf" msgid "Empty character constant" msgstr "" +#, fuzzy +msgid "Enable\\Enable the selected mod" +msgstr "Charger\\Charger la mission sélectionnée" + msgid "End of block missing" msgstr "Il manque la fin du bloc" @@ -764,6 +782,9 @@ msgstr "Infecté par un virus; ne fonctionne plus temporairement" msgid "Information exchange post" msgstr "Station relais" +msgid "Information:" +msgstr "" + msgid "Instruction \"break\" outside a loop" msgstr "Instruction \"break\" en dehors d'une boucle" @@ -854,18 +875,12 @@ msgstr "Liste des missions enregistrées" msgid "Load a saved mission" msgstr "Chargement d'une mission enregistrée" -msgid "Load\\Load Mod" -msgstr "" - msgid "Load\\Load a saved mission" msgstr "Charger\\Charger une mission enregistrée" msgid "Load\\Loads the selected mission" msgstr "Charger\\Charger la mission sélectionnée" -msgid "Loaded Mods:" -msgstr "" - msgid "Loading basic level settings" msgstr "Chargement des configurations de base du niveau" @@ -934,7 +949,13 @@ msgstr "Liste des missions du chapitre :" msgid "Missions\\Select mission" msgstr "Missions\\La grande aventure" -msgid "Mods\\Manage installed mods" +msgid "Mods" +msgstr "" + +msgid "Mods:" +msgstr "" + +msgid "Mods\\Mod manager" msgstr "" msgid "Mouse inversion X\\Inversion of the scrolling direction on the X axis" @@ -1105,7 +1126,7 @@ msgstr "Ouvrir" msgid "Open (Ctrl+O)" msgstr "Ouvrir (Ctrl+O)" -msgid "Open Directory\\Open Mods directory" +msgid "Open Directory\\Open the mods directory" msgstr "" msgid "Opening brace missing" @@ -1319,6 +1340,9 @@ msgstr "Drapeau rouge" msgid "Reflections on the buttons \\Shiny buttons" msgstr "Reflets sur les boutons\\Boutons brillants" +msgid "Refresh\\Refresh the list of currently installed mods" +msgstr "" + msgid "Remains of Apollo mission" msgstr "Vestige d'une mission Apollo" @@ -1603,6 +1627,9 @@ msgstr "" msgid "The types of the two operands are incompatible" msgstr "Les deux opérandes ne sont pas de types compatibles" +msgid "There are unsaved changes. Do you want to save them before leaving?" +msgstr "" + msgid "This class already exists" msgstr "Cette classe existe déjà" @@ -1736,15 +1763,12 @@ msgstr "Séquence d'échappement inconnue" msgid "Unknown function" msgstr "Routine inconnue" -msgid "Unload\\Unload Mod" -msgstr "" - -msgid "Unloaded Mods:" -msgstr "" - msgid "Up (\\key gup;)" msgstr "Monte (\\key gup;)" +msgid "Up\\Move the selected mod up so it's loaded sooner (mods may overwrite files from the mods above them)" +msgstr "" + msgid "Uranium deposit (site for derrick)" msgstr "Emplacement pour un derrick (minerai d'uranium)" @@ -1817,7 +1841,7 @@ msgstr "Robot renifleur volant" msgid "Withdraw shield (\\key action;)" msgstr "Refermer le bouclier (\\key action;)" -msgid "Workshop\\Open Workshop to search Mods" +msgid "Workshop\\Open the workshop to search for mods" msgstr "" msgid "Worm" @@ -2055,6 +2079,10 @@ msgstr "epsitec.com" #~ msgid "Mouse shadow\\Gives the mouse a shadow" #~ msgstr "Souris ombrée\\Jolie souris avec une ombre" +#, fuzzy +#~ msgid "No mods installed!" +#~ msgstr "Pas de niveaux spéciaux installés !" + #~ msgid "No other robot" #~ msgstr "Pas d'autre robot" diff --git a/po/pl.po b/po/pl.po index 9535ab56..251de7fe 100644 --- a/po/pl.po +++ b/po/pl.po @@ -124,6 +124,9 @@ msgstr "Wygląd\\Wybierz swoją postać" msgid "Apply changes\\Activates the changed settings" msgstr "Zastosuj zmiany\\Aktywuje zmienione ustawienia" +msgid "Apply\\Apply the current mod configuration" +msgstr "" + msgid "Appropriate constructor missing" msgstr "Brak odpowiedniego konstruktora" @@ -478,6 +481,10 @@ msgstr "Kopalnia" msgid "Descend\\Reduces the power of the jet" msgstr "W dół\\Zmniejsza moc silnika" +#, fuzzy +msgid "Description:" +msgstr "Rozdzielczość:" + msgid "Destroy" msgstr "Zniszcz" @@ -490,6 +497,10 @@ msgstr "Destroyer" msgid "Device\\Driver and resolution settings" msgstr "Urządzenie\\Ustawienia sterownika i rozdzielczości" +#, fuzzy +msgid "Disable\\Disable the selected mod" +msgstr "Usuń\\Usuwa zaznaczony plik" + msgid "Dividing by zero" msgstr "Dzielenie przez zero" @@ -506,6 +517,9 @@ msgstr "Drzwi zablokowane przez robota lub inny obiekt" msgid "Down (\\key gdown;)" msgstr "Dół (\\key gdown;)" +msgid "Down\\Move the selected mod down so it's loaded later (mods may overwrite files from the mods above them)" +msgstr "" + msgid "Drawer bot" msgstr "Robot rysownik" @@ -533,6 +547,10 @@ msgstr "Jajo" msgid "Empty character constant" msgstr "" +#, fuzzy +msgid "Enable\\Enable the selected mod" +msgstr "Wczytaj\\Wczytuje zaznaczoną misję" + msgid "End of block missing" msgstr "Brak końca bloku" @@ -759,6 +777,9 @@ msgstr "Zainfekowane wirusem, chwilowo niesprawne" msgid "Information exchange post" msgstr "Stacja przekaźnikowa informacji" +msgid "Information:" +msgstr "" + msgid "Instruction \"break\" outside a loop" msgstr "Polecenie \"break\" na zewnątrz pętli" @@ -849,18 +870,12 @@ msgstr "Lista zapisanych misji" msgid "Load a saved mission" msgstr "Wczytaj zapisaną misję" -msgid "Load\\Load Mod" -msgstr "" - msgid "Load\\Load a saved mission" msgstr "Wczytaj\\Wczytuje zapisaną misję" msgid "Load\\Loads the selected mission" msgstr "Wczytaj\\Wczytuje zaznaczoną misję" -msgid "Loaded Mods:" -msgstr "" - msgid "Loading basic level settings" msgstr "Wczytywanie ustawień poziomu" @@ -915,7 +930,13 @@ msgstr "Misje na tej planecie:" msgid "Missions\\Select mission" msgstr "Misje\\Wybierz misję" -msgid "Mods\\Manage installed mods" +msgid "Mods" +msgstr "" + +msgid "Mods:" +msgstr "" + +msgid "Mods\\Mod manager" msgstr "" msgid "Mouse inversion X\\Inversion of the scrolling direction on the X axis" @@ -1086,7 +1107,7 @@ msgstr "Otwórz" msgid "Open (Ctrl+O)" msgstr "Otwórz (Ctrl+O)" -msgid "Open Directory\\Open Mods directory" +msgid "Open Directory\\Open the mods directory" msgstr "" msgid "Opening brace missing" @@ -1299,6 +1320,9 @@ msgstr "Czerwona flaga" msgid "Reflections on the buttons \\Shiny buttons" msgstr "Odbicia na przyciskach \\Świecące przyciski" +msgid "Refresh\\Refresh the list of currently installed mods" +msgstr "" + msgid "Remains of Apollo mission" msgstr "Pozostałości z misji Apollo" @@ -1583,6 +1607,9 @@ msgstr "Nie udało się otworzyć ścieżki %s w przeglądarce plików." msgid "The types of the two operands are incompatible" msgstr "Niezgodne typy operatorów" +msgid "There are unsaved changes. Do you want to save them before leaving?" +msgstr "" + msgid "This class already exists" msgstr "Taka klasa już istnieje" @@ -1716,15 +1743,12 @@ msgstr "" msgid "Unknown function" msgstr "Funkcja nieznana" -msgid "Unload\\Unload Mod" -msgstr "" - -msgid "Unloaded Mods:" -msgstr "" - msgid "Up (\\key gup;)" msgstr "Góra (\\key gup;)" +msgid "Up\\Move the selected mod up so it's loaded sooner (mods may overwrite files from the mods above them)" +msgstr "" + msgid "Uranium deposit (site for derrick)" msgstr "Złoże uranu (miejsce na kopalnię)" @@ -1797,7 +1821,7 @@ msgstr "Szperacz latający" msgid "Withdraw shield (\\key action;)" msgstr "Wyłącz osłonę (\\key action;)" -msgid "Workshop\\Open Workshop to search Mods" +msgid "Workshop\\Open the workshop to search for mods" msgstr "" msgid "Worm" @@ -2034,6 +2058,10 @@ msgstr "epsitec.com" #~ msgid "Mouse shadow\\Gives the mouse a shadow" #~ msgstr "Cień kursora myszy\\Dodaje cień kursorowi myszy" +#, fuzzy +#~ msgid "No mods installed!" +#~ msgstr "Brak zainstalowanych poziomów użytkownika!" + #~ msgid "No other robot" #~ msgstr "Brak innego robota" diff --git a/po/pt.po b/po/pt.po index 159dd313..aed2d681 100644 --- a/po/pt.po +++ b/po/pt.po @@ -122,6 +122,9 @@ msgstr "Aparência\\Escolha sua aparência" msgid "Apply changes\\Activates the changed settings" msgstr "Aplicar mudanças\\Ativa as configurações alteradas" +msgid "Apply\\Apply the current mod configuration" +msgstr "" + msgid "Appropriate constructor missing" msgstr "Construtor apropriado faltando" @@ -477,6 +480,10 @@ msgstr "Extrator" msgid "Descend\\Reduces the power of the jet" msgstr "Descer\\Diminui o poder do jato" +#, fuzzy +msgid "Description:" +msgstr "Resolução:" + msgid "Destroy" msgstr "Destruir" @@ -489,6 +496,10 @@ msgstr "Destruidor" msgid "Device\\Driver and resolution settings" msgstr "Dispositivo\\Configurações de driver e resolução" +#, fuzzy +msgid "Disable\\Disable the selected mod" +msgstr "Excluir\\Exclui o arquivo selecionado" + msgid "Dividing by zero" msgstr "Dividindo por zero" @@ -505,6 +516,9 @@ msgstr "Portas bloqueadas por um robô ou outro objeto" msgid "Down (\\key gdown;)" msgstr "Baixo (\\key gdown;)" +msgid "Down\\Move the selected mod down so it's loaded later (mods may overwrite files from the mods above them)" +msgstr "" + msgid "Drawer bot" msgstr "Robô cartoonista" @@ -532,6 +546,10 @@ msgstr "Ovo" msgid "Empty character constant" msgstr "" +#, fuzzy +msgid "Enable\\Enable the selected mod" +msgstr "Carregar\\Carrega a missão selecionada" + msgid "End of block missing" msgstr "Fim do bloco ausente" @@ -759,6 +777,9 @@ msgstr "Infectado por vírus; temporariamento fora de serviço" msgid "Information exchange post" msgstr "Posto de troca de informação" +msgid "Information:" +msgstr "" + msgid "Instruction \"break\" outside a loop" msgstr "Intrução \"break\" fora de um laço" @@ -849,18 +870,12 @@ msgstr "Lista das missões salvas" msgid "Load a saved mission" msgstr "Carregar uma missão salva" -msgid "Load\\Load Mod" -msgstr "" - msgid "Load\\Load a saved mission" msgstr "Carregar\\Carregar uma missão salva" msgid "Load\\Loads the selected mission" msgstr "Carregar\\Carrega a missão selecionada" -msgid "Loaded Mods:" -msgstr "" - msgid "Loading basic level settings" msgstr "Carregando configurações de nível básico" @@ -929,7 +944,13 @@ msgstr "Lista de missões neste planeta:" msgid "Missions\\Select mission" msgstr "Missões\\Selecione uma missão" -msgid "Mods\\Manage installed mods" +msgid "Mods" +msgstr "" + +msgid "Mods:" +msgstr "" + +msgid "Mods\\Mod manager" msgstr "" msgid "Mouse inversion X\\Inversion of the scrolling direction on the X axis" @@ -1100,7 +1121,7 @@ msgstr "Abrir" msgid "Open (Ctrl+O)" msgstr "Abrir (Ctrl+O)" -msgid "Open Directory\\Open Mods directory" +msgid "Open Directory\\Open the mods directory" msgstr "" msgid "Opening brace missing" @@ -1314,6 +1335,9 @@ msgstr "Bandeira vermelha" msgid "Reflections on the buttons \\Shiny buttons" msgstr "Reflexões nos botões\\Botões brilhantes" +msgid "Refresh\\Refresh the list of currently installed mods" +msgstr "" + msgid "Remains of Apollo mission" msgstr "Restos da missão Apollo" @@ -1598,6 +1622,9 @@ msgstr "" msgid "The types of the two operands are incompatible" msgstr "Os tipos dos dois operandos são incompativeis" +msgid "There are unsaved changes. Do you want to save them before leaving?" +msgstr "" + msgid "This class already exists" msgstr "Esta classe já existe" @@ -1731,15 +1758,12 @@ msgstr "Sequência de escape desconhecidade" msgid "Unknown function" msgstr "Função desconhecida" -msgid "Unload\\Unload Mod" -msgstr "" - -msgid "Unloaded Mods:" -msgstr "" - msgid "Up (\\key gup;)" msgstr "Cima (\\key gup;)" +msgid "Up\\Move the selected mod up so it's loaded sooner (mods may overwrite files from the mods above them)" +msgstr "" + msgid "Uranium deposit (site for derrick)" msgstr "Depósito de urânio (local para extrator)" @@ -1812,7 +1836,7 @@ msgstr "Farejador alado" msgid "Withdraw shield (\\key action;)" msgstr "Retirar escudo (\\key action;)" -msgid "Workshop\\Open Workshop to search Mods" +msgid "Workshop\\Open the workshop to search for mods" msgstr "" msgid "Worm" @@ -2053,6 +2077,10 @@ msgstr "epsitec.com" #~ msgid "Mouse shadow\\Gives the mouse a shadow" #~ msgstr "Souris ombrée\\Jolie souris avec une ombre" +#, fuzzy +#~ msgid "No mods installed!" +#~ msgstr "Nenhum nível de usuário instalado!" + #~ msgid "No other robot" #~ msgstr "Pas d'autre robot" diff --git a/po/ru.po b/po/ru.po index 04d9187a..d450ccf4 100644 --- a/po/ru.po +++ b/po/ru.po @@ -124,6 +124,9 @@ msgstr "Внешность\\Настройка внешности" msgid "Apply changes\\Activates the changed settings" msgstr "Принять\\Принять изменения настроек" +msgid "Apply\\Apply the current mod configuration" +msgstr "" + msgid "Appropriate constructor missing" msgstr "Соответствующий конструктор отсутствует" @@ -486,6 +489,10 @@ msgstr "Космический корабль" msgid "Descend\\Reduces the power of the jet" msgstr "Снижение и посадка\\Понижение мощности реактивного двигателя" +#, fuzzy +msgid "Description:" +msgstr "Разрешение:" + msgid "Destroy" msgstr "Уничтожить" @@ -498,6 +505,10 @@ msgstr "Уничтожитель" msgid "Device\\Driver and resolution settings" msgstr "Устройство\\Драйвер и настройки разрешения" +#, fuzzy +msgid "Disable\\Disable the selected mod" +msgstr "Удалить\\Удаление выбранного файла" + msgid "Dividing by zero" msgstr "Деление на ноль (запрещено!)" @@ -514,6 +525,9 @@ msgstr "Двери заблокированы роботом или другим msgid "Down (\\key gdown;)" msgstr "Вниз (\\key gdown;)" +msgid "Down\\Move the selected mod down so it's loaded later (mods may overwrite files from the mods above them)" +msgstr "" + msgid "Drawer bot" msgstr "Рисовальщик" @@ -541,6 +555,10 @@ msgstr "Яйцо" msgid "Empty character constant" msgstr "" +#, fuzzy +msgid "Enable\\Enable the selected mod" +msgstr "Загрузить\\Загрузить выбранную миссию" + msgid "End of block missing" msgstr "Отсутствует конец блока" @@ -768,6 +786,9 @@ msgstr "Заражено вирусом. Временно вышел из стр msgid "Information exchange post" msgstr "Пост обмена информацией" +msgid "Information:" +msgstr "" + msgid "Instruction \"break\" outside a loop" msgstr "Инструкция \"break\" вне цикла" @@ -858,18 +879,12 @@ msgstr "Список сохраненных миссий" msgid "Load a saved mission" msgstr "Загрузить" -msgid "Load\\Load Mod" -msgstr "" - msgid "Load\\Load a saved mission" msgstr "Загрузить\\Загрузить сохраненную миссию" msgid "Load\\Loads the selected mission" msgstr "Загрузить\\Загрузить выбранную миссию" -msgid "Loaded Mods:" -msgstr "" - msgid "Loading basic level settings" msgstr "Загрузка основных настроек уровня" @@ -938,7 +953,13 @@ msgstr "Миссии на этой планете:" msgid "Missions\\Select mission" msgstr "Миссии\\Выбор миссии" -msgid "Mods\\Manage installed mods" +msgid "Mods" +msgstr "" + +msgid "Mods:" +msgstr "" + +msgid "Mods\\Mod manager" msgstr "" msgid "Mouse inversion X\\Inversion of the scrolling direction on the X axis" @@ -1111,7 +1132,7 @@ msgstr "Открыть" msgid "Open (Ctrl+O)" msgstr "Открыть (Ctrl+O)" -msgid "Open Directory\\Open Mods directory" +msgid "Open Directory\\Open the mods directory" msgstr "" msgid "Opening brace missing" @@ -1326,6 +1347,9 @@ msgstr "Красный флаг" msgid "Reflections on the buttons \\Shiny buttons" msgstr "Отражения на кнопках \\Блестящие кнопки" +msgid "Refresh\\Refresh the list of currently installed mods" +msgstr "" + msgid "Remains of Apollo mission" msgstr "Остатки миссии Аполлон" @@ -1614,6 +1638,9 @@ msgstr "" msgid "The types of the two operands are incompatible" msgstr "Типы операндов несовместимы" +msgid "There are unsaved changes. Do you want to save them before leaving?" +msgstr "" + msgid "This class already exists" msgstr "Этот класс уже существует" @@ -1747,15 +1774,12 @@ msgstr "" msgid "Unknown function" msgstr "Неизвестная функция" -msgid "Unload\\Unload Mod" -msgstr "" - -msgid "Unloaded Mods:" -msgstr "" - msgid "Up (\\key gup;)" msgstr "Вверх (\\key gup;)" +msgid "Up\\Move the selected mod up so it's loaded sooner (mods may overwrite files from the mods above them)" +msgstr "" + msgid "Uranium deposit (site for derrick)" msgstr "Запасы урана (место для буровой вышки)" @@ -1828,7 +1852,7 @@ msgstr "Летающий искатель" msgid "Withdraw shield (\\key action;)" msgstr "Снять щит (\\key action;)" -msgid "Workshop\\Open Workshop to search Mods" +msgid "Workshop\\Open the workshop to search for mods" msgstr "" msgid "Worm" @@ -2063,6 +2087,10 @@ msgstr "epsitec.com" #~ msgid "Mouse shadow\\Gives the mouse a shadow" #~ msgstr "Тень мыши\\Мышь отбрасывает тень" +#, fuzzy +#~ msgid "No mods installed!" +#~ msgstr "Не установленны пользовательские уровни!" + #~ msgid "No other robot" #~ msgstr "Нет робота" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f70489ab..df752615 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -569,6 +569,8 @@ set(BASE_SOURCES ui/screen/screen_loading.h ui/screen/screen_main_menu.cpp ui/screen/screen_main_menu.h + ui/screen/screen_mod_list.cpp + ui/screen/screen_mod_list.h ui/screen/screen_player_select.cpp ui/screen/screen_player_select.h ui/screen/screen_quit.cpp @@ -583,8 +585,6 @@ set(BASE_SOURCES ui/screen/screen_setup_game.h ui/screen/screen_setup_graphics.cpp ui/screen/screen_setup_graphics.h - ui/screen/screen_setup_mods.cpp - ui/screen/screen_setup_mods.h ui/screen/screen_setup_sound.cpp ui/screen/screen_setup_sound.h ui/screen/screen_welcome.cpp diff --git a/src/app/modman.cpp b/src/app/modman.cpp index e2fb3468..cf552641 100644 --- a/src/app/modman.cpp +++ b/src/app/modman.cpp @@ -30,9 +30,10 @@ #include "common/resources/resourcemanager.h" #include -#include +#include #include #include +#include "modman.h" using namespace boost::filesystem; @@ -104,26 +105,40 @@ void CModManager::FindMods() } } -void CModManager::EnableMod(const std::string& modName) +void CModManager::EnableMod(size_t i) { - Mod* mod = FindMod(modName); - if (!mod) - { - GetLogger()->Error("Could not enable mod: %s not found\n", modName.c_str()); - return; - } - mod->enabled = true; + m_mods[i].enabled = true; } -void CModManager::DisableMod(const std::string& modName) +void CModManager::DisableMod(size_t i) { - Mod* mod = FindMod(modName); - if (!mod) + m_mods[i].enabled = false; +} + +size_t CModManager::MoveUp(size_t i) +{ + if (i != 0) { - GetLogger()->Error("Could not disable mod: %s not found\n", modName.c_str()); - return; + std::swap(m_mods[i - 1], m_mods[i]); + return i - 1; + } + else + { + return i; + } +} + +size_t CModManager::MoveDown(size_t i) +{ + if (i != m_mods.size() - 1) + { + std::swap(m_mods[i], m_mods[i + 1]); + return i + 1; + } + else + { + return i; } - mod->enabled = false; } void CModManager::UpdatePaths() @@ -158,19 +173,17 @@ void CModManager::SaveMods() GetConfigFile().Save(); } -boost::optional CModManager::GetMod(const std::string& modName) +size_t CModManager::CountMods() const { - Mod* mod = FindMod(modName); - return mod != nullptr ? *mod : boost::optional(); + return m_mods.size(); +} + +const Mod& CModManager::GetMod(size_t i) const +{ + return m_mods[i]; } const std::vector& CModManager::GetMods() const { return m_mods; } - -Mod* CModManager::FindMod(const std::string& modName) -{ - auto it = std::find_if(m_mods.begin(), m_mods.end(), [&](Mod& mod) { return mod.name == modName; }); - return it != m_mods.end() ? &(*it) : nullptr; -} diff --git a/src/app/modman.h b/src/app/modman.h index 5ce3efa2..984d54ea 100644 --- a/src/app/modman.h +++ b/src/app/modman.h @@ -37,11 +37,17 @@ struct Mod }; /** - * \class CApplication - * \brief Main application + * \class CModManager + * \brief This class handles the list of mods. * - * This class handles the list of currently loaded mods. - * The order matters since the order in which files are loaded matters. + * The order matters since the order in which files are loaded matters, + * because some files can be overwritten. + * + * The list can be kept in the config file with the \ref SaveMods function. + * + * The changes in the list do not immediately apply. + * Separate calls to \ref UpdatePaths and \ref ReloadResources, probably in this order, + * need to be done for the changes to apply. * */ class CModManager @@ -53,10 +59,16 @@ public: void FindMods(); //! Removes a mod from the list of loaded mods - void EnableMod(const std::string& modName); + void EnableMod(size_t i); //! Adds a mod to the list of loaded mods - void DisableMod(const std::string& modName); + void DisableMod(size_t i); + + //! Moves the selected mod up in the list so that it's loaded sooner than others, returns the new index + size_t MoveUp(size_t i); + + //! Moves the selected mod down in the list so that it's loaded later than others, returns the new index + size_t MoveDown(size_t i); //! Reloads application resources so the enabled mods are applied void ReloadResources(); @@ -67,11 +79,14 @@ public: //! Updates the paths in Path Manager according to the current mod configuration void UpdatePaths(); - boost::optional GetMod(const std::string& modName); - const std::vector& GetMods() const; + //! Number of mods loaded + size_t CountMods() const; -private: - Mod* FindMod(const std::string& modName); + //! Returns the reference to the mod in given position + const Mod& GetMod(size_t i) const; + + //! Returns the list of mods + const std::vector& GetMods() const; private: CApplication* m_app; diff --git a/src/common/event.cpp b/src/common/event.cpp index 3de67fc1..5bae84f2 100644 --- a/src/common/event.cpp +++ b/src/common/event.cpp @@ -190,6 +190,7 @@ void InitializeEventTypeTexts() EVENT_TYPE_TEXT[EVENT_INTERFACE_ABORT] = "EVENT_INTERFACE_ABORT"; EVENT_TYPE_TEXT[EVENT_INTERFACE_USER] = "EVENT_INTERFACE_USER"; EVENT_TYPE_TEXT[EVENT_INTERFACE_SATCOM] = "EVENT_INTERFACE_SATCOM"; + EVENT_TYPE_TEXT[EVENT_INTERFACE_MODS] = "EVENT_INTERFACE_MODS"; EVENT_TYPE_TEXT[EVENT_INTERFACE_CHAP] = "EVENT_INTERFACE_CHAP"; EVENT_TYPE_TEXT[EVENT_INTERFACE_LIST] = "EVENT_INTERFACE_LIST"; @@ -201,7 +202,6 @@ void InitializeEventTypeTexts() EVENT_TYPE_TEXT[EVENT_INTERFACE_SETUPp] = "EVENT_INTERFACE_SETUPp"; EVENT_TYPE_TEXT[EVENT_INTERFACE_SETUPc] = "EVENT_INTERFACE_SETUPc"; EVENT_TYPE_TEXT[EVENT_INTERFACE_SETUPs] = "EVENT_INTERFACE_SETUPs"; - EVENT_TYPE_TEXT[EVENT_INTERFACE_SETUPm] = "EVENT_INTERFACE_SETUPm"; EVENT_TYPE_TEXT[EVENT_INTERFACE_DEVICE] = "EVENT_INTERFACE_DEVICE"; EVENT_TYPE_TEXT[EVENT_INTERFACE_RESOL] = "EVENT_INTERFACE_RESOL"; @@ -273,12 +273,15 @@ void InitializeEventTypeTexts() EVENT_TYPE_TEXT[EVENT_INTERFACE_JOYSTICK_CAM_Y_INVERT]= "EVENT_INTERFACE_JOYSTICK_CAM_Y_INVERT"; EVENT_TYPE_TEXT[EVENT_INTERFACE_JOYSTICK_CAM_Z_INVERT]= "EVENT_INTERFACE_JOYSTICK_CAM_Z_INVERT"; - EVENT_TYPE_TEXT[EVENT_INTERFACE_MODS_UNLOADED] = "EVENT_INTERFACE_MODS_UNLOADED"; - EVENT_TYPE_TEXT[EVENT_INTERFACE_MODS_LOADED] = "EVENT_INTERFACE_MODS_LOADED"; + EVENT_TYPE_TEXT[EVENT_INTERFACE_MOD_LIST] = "EVENT_INTERFACE_MOD_LIST"; EVENT_TYPE_TEXT[EVENT_INTERFACE_WORKSHOP] = "EVENT_INTERFACE_WORKSHOP"; EVENT_TYPE_TEXT[EVENT_INTERFACE_MODS_DIR] = "EVENT_INTERFACE_MODS_DIR"; - EVENT_TYPE_TEXT[EVENT_INTERFACE_LOAD] = "EVENT_INTERFACE_LOAD"; - EVENT_TYPE_TEXT[EVENT_INTERFACE_UNLOAD] = "EVENT_INTERFACE_UNLOAD"; + EVENT_TYPE_TEXT[EVENT_INTERFACE_MOD_ENABLE_OR_DISABLE] = "EVENT_INTERFACE_MOD_ENABLE_OR_DISABLE"; + EVENT_TYPE_TEXT[EVENT_INTERFACE_MODS_APPLY] = "EVENT_INTERFACE_MODS_APPLY"; + EVENT_TYPE_TEXT[EVENT_INTERFACE_MOD_DETAILS] = "EVENT_INTERFACE_MOD_DETAILS"; + EVENT_TYPE_TEXT[EVENT_INTERFACE_MOD_MOVE_UP] = "EVENT_INTERFACE_MOD_MOVE_UP"; + EVENT_TYPE_TEXT[EVENT_INTERFACE_MOD_MOVE_DOWN] = "EVENT_INTERFACE_MOD_MOVE_DOWN"; + EVENT_TYPE_TEXT[EVENT_INTERFACE_MODS_REFRESH] = "EVENT_INTERFACE_MODS_REFRESH"; EVENT_TYPE_TEXT[EVENT_INTERFACE_GLINTl] = "EVENT_INTERFACE_GLINTl"; EVENT_TYPE_TEXT[EVENT_INTERFACE_GLINTr] = "EVENT_INTERFACE_GLINTr"; diff --git a/src/common/event.h b/src/common/event.h index 91d79439..d55c9664 100644 --- a/src/common/event.h +++ b/src/common/event.h @@ -225,6 +225,7 @@ enum EventType EVENT_INTERFACE_ABORT = 412, EVENT_INTERFACE_USER = 413, EVENT_INTERFACE_SATCOM = 414, + EVENT_INTERFACE_MODS = 416, EVENT_INTERFACE_CHAP = 420, EVENT_INTERFACE_LIST = 421, @@ -236,7 +237,6 @@ enum EventType EVENT_INTERFACE_SETUPp = 432, EVENT_INTERFACE_SETUPc = 433, EVENT_INTERFACE_SETUPs = 434, - EVENT_INTERFACE_SETUPm = 435, EVENT_INTERFACE_DEVICE = 440, EVENT_INTERFACE_RESOL = 441, @@ -312,12 +312,16 @@ enum EventType EVENT_INTERFACE_JOYSTICK_CAM_Y_INVERT = 573, EVENT_INTERFACE_JOYSTICK_CAM_Z_INVERT = 574, - EVENT_INTERFACE_MODS_UNLOADED = 580, - EVENT_INTERFACE_MODS_LOADED = 581, - EVENT_INTERFACE_WORKSHOP = 582, - EVENT_INTERFACE_MODS_DIR = 583, - EVENT_INTERFACE_LOAD = 584, - EVENT_INTERFACE_UNLOAD = 585, + EVENT_INTERFACE_MOD_LIST = 580, + EVENT_INTERFACE_WORKSHOP = 581, + EVENT_INTERFACE_MODS_DIR = 582, + EVENT_INTERFACE_MOD_ENABLE_OR_DISABLE = 583, + EVENT_INTERFACE_MODS_APPLY = 584, + EVENT_INTERFACE_MOD_SUMMARY = 585, + EVENT_INTERFACE_MOD_DETAILS = 586, + EVENT_INTERFACE_MOD_MOVE_UP = 587, + EVENT_INTERFACE_MOD_MOVE_DOWN = 888, + EVENT_INTERFACE_MODS_REFRESH = 589, EVENT_INTERFACE_GLINTl = 590, EVENT_INTERFACE_GLINTr = 591, diff --git a/src/common/restext.cpp b/src/common/restext.cpp index 11270e46..664b8ac3 100644 --- a/src/common/restext.cpp +++ b/src/common/restext.cpp @@ -71,12 +71,13 @@ void InitializeRestext() stringsText[RT_TITLE_MISSION] = TR("Missions"); stringsText[RT_TITLE_FREE] = TR("Free game"); stringsText[RT_TITLE_USER] = TR("User levels"); - stringsText[RT_TITLE_CODE_BATTLES]=TR("Code battles"); + stringsText[RT_TITLE_CODE_BATTLES] = TR("Code battles"); stringsText[RT_TITLE_SETUP] = TR("Options"); stringsText[RT_TITLE_NAME] = TR("Player's name"); stringsText[RT_TITLE_PERSO] = TR("Customize your appearance"); stringsText[RT_TITLE_WRITE] = TR("Save the current mission"); stringsText[RT_TITLE_READ] = TR("Load a saved mission"); + stringsText[RT_TITLE_MODS] = TR("Mods"); stringsText[RT_PLAY_CHAP_CHAPTERS] = TR("Chapters:"); stringsText[RT_PLAY_CHAP_PLANETS] = TR("Planets:"); @@ -92,8 +93,11 @@ void InitializeRestext() stringsText[RT_SETUP_KEY1] = TR("1) First click on the key you want to redefine."); stringsText[RT_SETUP_KEY2] = TR("2) Then press the key you want to use instead."); - stringsText[RT_MODS_UNLOADED] = TR("Unloaded Mods:"); - stringsText[RT_MODS_LOADED] = TR("Loaded Mods:"); + stringsText[RT_MOD_LIST] = TR("Mods:"); + stringsText[RT_MOD_DETAILS] = TR("Information:"); + stringsText[RT_MOD_SUMMARY] = TR("Description:"); + stringsText[RT_MOD_ENABLE] = TR("Enable\\Enable the selected mod"); + stringsText[RT_MOD_DISABLE] = TR("Disable\\Disable the selected mod"); stringsText[RT_PERSO_FACE] = TR("Face type:"); stringsText[RT_PERSO_GLASSES] = TR("Eyeglasses:"); @@ -115,6 +119,7 @@ void InitializeRestext() stringsText[RT_DIALOG_OPEN_PATH_FAILED_TEXT] = TR("The path %s could not be opened in a file explorer."); stringsText[RT_DIALOG_OPEN_WEBSITE_FAILED_TITLE] = TR("Could not open the web browser!"); stringsText[RT_DIALOG_OPEN_WEBSITE_FAILED_TEXT] = TR("The address %s could not be opened in a web browser."); + stringsText[RT_DIALOG_CHANGES_QUESTION] = TR("There are unsaved changes. Do you want to save them before leaving?"); stringsText[RT_STUDIO_LISTTT] = TR("Keyword help(\\key cbot;)"); stringsText[RT_STUDIO_COMPOK] = TR("Compilation ok (0 errors)"); @@ -180,6 +185,7 @@ void InitializeRestext() stringsEvent[EVENT_INTERFACE_CODE_BATTLES] = TR("Code battles\\Program your robot to be the best of them all!"); stringsEvent[EVENT_INTERFACE_USER] = TR("Custom levels\\Levels from mods created by the users"); stringsEvent[EVENT_INTERFACE_SATCOM] = TR("SatCom"); + stringsEvent[EVENT_INTERFACE_MODS] = TR("Mods\\Mod manager"); stringsEvent[EVENT_INTERFACE_NAME] = TR("Change player\\Change player"); stringsEvent[EVENT_INTERFACE_SETUP] = TR("Options\\Preferences"); stringsEvent[EVENT_INTERFACE_AGAIN] = TR("Restart\\Restart the mission from the beginning"); @@ -189,16 +195,17 @@ void InitializeRestext() stringsEvent[EVENT_INTERFACE_QUIT] = TR("Quit\\Quit Colobot: Gold Edition"); stringsEvent[EVENT_INTERFACE_BACK] = TR("<< Back \\Back to the previous screen"); stringsEvent[EVENT_INTERFACE_PLAY] = TR("Play\\Start mission!"); - stringsEvent[EVENT_INTERFACE_WORKSHOP] = TR("Workshop\\Open Workshop to search Mods"); - stringsEvent[EVENT_INTERFACE_MODS_DIR] = TR("Open Directory\\Open Mods directory"); - stringsEvent[EVENT_INTERFACE_LOAD] = TR("Load\\Load Mod"); - stringsEvent[EVENT_INTERFACE_UNLOAD] = TR("Unload\\Unload Mod"); + stringsEvent[EVENT_INTERFACE_WORKSHOP] = TR("Workshop\\Open the workshop to search for mods"); + stringsEvent[EVENT_INTERFACE_MODS_DIR] = TR("Open Directory\\Open the mods directory"); + stringsEvent[EVENT_INTERFACE_MODS_APPLY] = TR("Apply\\Apply the current mod configuration"); + stringsEvent[EVENT_INTERFACE_MOD_MOVE_UP] = TR("Up\\Move the selected mod up so it's loaded sooner (mods may overwrite files from the mods above them)"); + stringsEvent[EVENT_INTERFACE_MOD_MOVE_DOWN] = TR("Down\\Move the selected mod down so it's loaded later (mods may overwrite files from the mods above them)"); + stringsEvent[EVENT_INTERFACE_MODS_REFRESH] = TR("Refresh\\Refresh the list of currently installed mods"); stringsEvent[EVENT_INTERFACE_SETUPd] = TR("Device\\Driver and resolution settings"); stringsEvent[EVENT_INTERFACE_SETUPg] = TR("Graphics\\Graphics settings"); stringsEvent[EVENT_INTERFACE_SETUPp] = TR("Game\\Game settings"); stringsEvent[EVENT_INTERFACE_SETUPc] = TR("Controls\\Keyboard, joystick and mouse settings"); stringsEvent[EVENT_INTERFACE_SETUPs] = TR("Sound\\Music and game sound volume"); - stringsEvent[EVENT_INTERFACE_SETUPm] = TR("Mods\\Manage installed mods"); stringsEvent[EVENT_INTERFACE_DEVICE] = TR("Unit"); stringsEvent[EVENT_INTERFACE_RESOL] = TR("Resolution"); stringsEvent[EVENT_INTERFACE_FULL] = TR("Full screen\\Full screen or window mode"); diff --git a/src/common/restext.h b/src/common/restext.h index 9edf4105..241b6c38 100644 --- a/src/common/restext.h +++ b/src/common/restext.h @@ -71,6 +71,7 @@ enum ResTextType RT_TITLE_WRITE = 50, RT_TITLE_READ = 51, RT_TITLE_USER = 52, + RT_TITLE_MODS = 54, RT_PLAY_CHAP_CHAPTERS = 60, RT_PLAY_CHAP_PLANETS = 61, @@ -86,9 +87,6 @@ enum ResTextType RT_SETUP_KEY1 = 82, RT_SETUP_KEY2 = 83, - RT_MODS_UNLOADED = 85, - RT_MODS_LOADED = 86, - RT_PERSO_FACE = 90, RT_PERSO_GLASSES = 91, RT_PERSO_HAIR = 92, @@ -109,6 +107,7 @@ enum ResTextType RT_DIALOG_OPEN_PATH_FAILED_TEXT = 114, RT_DIALOG_OPEN_WEBSITE_FAILED_TITLE = 115, RT_DIALOG_OPEN_WEBSITE_FAILED_TEXT = 116, + RT_DIALOG_CHANGES_QUESTION = 117, RT_STUDIO_LISTTT = 120, RT_STUDIO_COMPOK = 121, @@ -154,6 +153,11 @@ enum ResTextType RT_SCOREBOARD_RESULTS_TIME= 232, RT_SCOREBOARD_RESULTS_LINE= 233, + RT_MOD_LIST = 234, + RT_MOD_DETAILS = 235, + RT_MOD_SUMMARY = 236, + RT_MOD_ENABLE = 237, + RT_MOD_DISABLE = 238, RT_MAX //! < number of values }; diff --git a/src/level/robotmain.cpp b/src/level/robotmain.cpp index b9e3633f..7092b32b 100644 --- a/src/level/robotmain.cpp +++ b/src/level/robotmain.cpp @@ -320,19 +320,18 @@ std::string PhaseToString(Phase phase) if (phase == PHASE_APPERANCE) return "PHASE_APPERANCE"; if (phase == PHASE_MAIN_MENU) return "PHASE_MAIN_MENU"; if (phase == PHASE_LEVEL_LIST) return "PHASE_LEVEL_LIST"; + if (phase == PHASE_MOD_LIST) return "PHASE_MOD_LIST"; if (phase == PHASE_SIMUL) return "PHASE_SIMUL"; if (phase == PHASE_SETUPd) return "PHASE_SETUPd"; if (phase == PHASE_SETUPg) return "PHASE_SETUPg"; if (phase == PHASE_SETUPp) return "PHASE_SETUPp"; if (phase == PHASE_SETUPc) return "PHASE_SETUPc"; if (phase == PHASE_SETUPs) return "PHASE_SETUPs"; - if (phase == PHASE_SETUPm) return "PHASE_SETUPm"; if (phase == PHASE_SETUPds) return "PHASE_SETUPds"; if (phase == PHASE_SETUPgs) return "PHASE_SETUPgs"; if (phase == PHASE_SETUPps) return "PHASE_SETUPps"; if (phase == PHASE_SETUPcs) return "PHASE_SETUPcs"; if (phase == PHASE_SETUPss) return "PHASE_SETUPss"; - if (phase == PHASE_SETUPms) return "PHASE_SETUPms"; if (phase == PHASE_WRITEs) return "PHASE_WRITEs"; if (phase == PHASE_READ) return "PHASE_READ"; if (phase == PHASE_READs) return "PHASE_READs"; @@ -345,7 +344,7 @@ std::string PhaseToString(Phase phase) bool IsInSimulationConfigPhase(Phase phase) { - return (phase >= PHASE_SETUPds && phase <= PHASE_SETUPms) || phase == PHASE_READs || phase == PHASE_WRITEs; + return (phase >= PHASE_SETUPds && phase <= PHASE_SETUPss) || phase == PHASE_READs || phase == PHASE_WRITEs; } bool IsPhaseWithWorld(Phase phase) @@ -3913,7 +3912,7 @@ void CRobotMain::ChangeColor() m_phase != PHASE_SETUPps && m_phase != PHASE_SETUPcs && m_phase != PHASE_SETUPss && - m_phase != PHASE_SETUPms && + m_phase != PHASE_MOD_LIST && m_phase != PHASE_WIN && m_phase != PHASE_LOST && m_phase != PHASE_APPERANCE ) return; diff --git a/src/level/robotmain.h b/src/level/robotmain.h index b339cfdc..731d7a1a 100644 --- a/src/level/robotmain.h +++ b/src/level/robotmain.h @@ -55,19 +55,18 @@ enum Phase PHASE_APPERANCE, PHASE_MAIN_MENU, PHASE_LEVEL_LIST, + PHASE_MOD_LIST, PHASE_SIMUL, PHASE_SETUPd, PHASE_SETUPg, PHASE_SETUPp, PHASE_SETUPc, PHASE_SETUPs, - PHASE_SETUPm, PHASE_SETUPds, PHASE_SETUPgs, PHASE_SETUPps, PHASE_SETUPcs, PHASE_SETUPss, - PHASE_SETUPms, PHASE_WRITEs, PHASE_READ, PHASE_READs, diff --git a/src/ui/maindialog.cpp b/src/ui/maindialog.cpp index b21070fb..5cdfdd47 100644 --- a/src/ui/maindialog.cpp +++ b/src/ui/maindialog.cpp @@ -107,7 +107,6 @@ bool CMainDialog::EventProcess(const Event &event) if ( CScreenSetup::GetTab() == PHASE_SETUPp ) m_main->ChangePhase(PHASE_SETUPps); if ( CScreenSetup::GetTab() == PHASE_SETUPc ) m_main->ChangePhase(PHASE_SETUPcs); if ( CScreenSetup::GetTab() == PHASE_SETUPs ) m_main->ChangePhase(PHASE_SETUPss); - if ( CScreenSetup::GetTab() == PHASE_SETUPm ) m_main->ChangePhase(PHASE_SETUPss); } if ( pressedButton == EVENT_INTERFACE_WRITE ) diff --git a/src/ui/mainui.cpp b/src/ui/mainui.cpp index 57436f89..daca36c7 100644 --- a/src/ui/mainui.cpp +++ b/src/ui/mainui.cpp @@ -49,13 +49,13 @@ #include "ui/screen/screen_level_list.h" #include "ui/screen/screen_loading.h" #include "ui/screen/screen_main_menu.h" +#include "ui/screen/screen_mod_list.h" #include "ui/screen/screen_player_select.h" #include "ui/screen/screen_quit.h" #include "ui/screen/screen_setup_controls.h" #include "ui/screen/screen_setup_display.h" #include "ui/screen/screen_setup_game.h" #include "ui/screen/screen_setup_graphics.h" -#include "ui/screen/screen_setup_mods.h" #include "ui/screen/screen_setup_sound.h" #include "ui/screen/screen_welcome.h" @@ -81,11 +81,11 @@ CMainUserInterface::CMainUserInterface() m_screenIORead = MakeUnique(m_screenLevelList.get()); m_screenIOWrite = MakeUnique(m_screenLevelList.get()); m_screenLoading = MakeUnique(); + m_screenModList = MakeUnique(m_dialog.get(), m_app->GetModManager()); m_screenSetupControls = MakeUnique(); m_screenSetupDisplay = MakeUnique(); m_screenSetupGame = MakeUnique(); m_screenSetupGraphics = MakeUnique(); - m_screenSetupMods = MakeUnique(m_dialog.get(), m_app->GetModManager()); m_screenSetupSound = MakeUnique(); m_screenMainMenu = MakeUnique(); m_screenPlayerSelect = MakeUnique(m_dialog.get()); @@ -146,7 +146,6 @@ CScreenSetup* CMainUserInterface::GetSetupScreen(Phase phase) if(phase == PHASE_SETUPp) return m_screenSetupGame.get(); if(phase == PHASE_SETUPc) return m_screenSetupControls.get(); if(phase == PHASE_SETUPs) return m_screenSetupSound.get(); - if(phase == PHASE_SETUPm) return m_screenSetupMods.get(); assert(false); return nullptr; } @@ -187,14 +186,18 @@ void CMainUserInterface::ChangePhase(Phase phase) m_screenLevelList->SetLevelCategory(m_main->GetLevelCategory()); m_currentScreen = m_screenLevelList.get(); } - if (m_phase >= PHASE_SETUPd && m_phase <= PHASE_SETUPm) + if (m_phase == PHASE_MOD_LIST) + { + m_currentScreen = m_screenModList.get(); + } + if (m_phase >= PHASE_SETUPd && m_phase <= PHASE_SETUPs) { CScreenSetup* screenSetup = GetSetupScreen(m_phase); screenSetup->SetInSimulation(false); screenSetup->SetActive(); m_currentScreen = screenSetup; } - if (m_phase >= PHASE_SETUPds && m_phase <= PHASE_SETUPms) + if (m_phase >= PHASE_SETUPds && m_phase <= PHASE_SETUPss) { CScreenSetup* screenSetup = GetSetupScreen(static_cast(m_phase - PHASE_SETUPds + PHASE_SETUPd)); screenSetup->SetInSimulation(true); @@ -350,7 +353,6 @@ void CMainUserInterface::GlintMove() m_phase == PHASE_SETUPp || m_phase == PHASE_SETUPc || m_phase == PHASE_SETUPs || - m_phase == PHASE_SETUPm || m_phase == PHASE_SETUPds || m_phase == PHASE_SETUPgs || m_phase == PHASE_SETUPps || @@ -535,12 +537,12 @@ void CMainUserInterface::FrameParticle(float rTime) } else if ( m_phase == PHASE_PLAYER_SELECT || m_phase == PHASE_LEVEL_LIST || + m_phase == PHASE_MOD_LIST || m_phase == PHASE_SETUPd || m_phase == PHASE_SETUPg || m_phase == PHASE_SETUPp || m_phase == PHASE_SETUPc || m_phase == PHASE_SETUPs || - m_phase == PHASE_SETUPm || m_phase == PHASE_READ ) { pParti = partiPosBig; diff --git a/src/ui/mainui.h b/src/ui/mainui.h index 76440a40..2cae1d18 100644 --- a/src/ui/mainui.h +++ b/src/ui/mainui.h @@ -50,6 +50,7 @@ class CScreenIOWrite; class CScreenLevelList; class CScreenLoading; class CScreenMainMenu; +class CScreenModList; class CScreenPlayerSelect; class CScreenQuit; class CScreenSetup; @@ -57,7 +58,6 @@ class CScreenSetupControls; class CScreenSetupDisplay; class CScreenSetupGame; class CScreenSetupGraphics; -class CScreenSetupMods; class CScreenSetupSound; class CScreenWelcome; @@ -115,13 +115,13 @@ protected: std::unique_ptr m_screenLevelList; std::unique_ptr m_screenLoading; std::unique_ptr m_screenMainMenu; + std::unique_ptr m_screenModList; std::unique_ptr m_screenPlayerSelect; std::unique_ptr m_screenQuit; std::unique_ptr m_screenSetupControls; std::unique_ptr m_screenSetupDisplay; std::unique_ptr m_screenSetupGame; std::unique_ptr m_screenSetupGraphics; - std::unique_ptr m_screenSetupMods; std::unique_ptr m_screenSetupSound; std::unique_ptr m_screenWelcome; diff --git a/src/ui/screen/screen_main_menu.cpp b/src/ui/screen/screen_main_menu.cpp index 2d69ae1c..30c771a0 100644 --- a/src/ui/screen/screen_main_menu.cpp +++ b/src/ui/screen/screen_main_menu.cpp @@ -170,6 +170,13 @@ void CScreenMainMenu::CreateInterface() pb = pw->CreateButton(pos, ddim, 128+60, EVENT_INTERFACE_SATCOM); pb->SetState(STATE_SHADOW); + // Mods button + pos.x = 447.0f/640.0f; + pos.y = 313.0f/480.0f; + ddim.x = 0.09f; + pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_MODS); + pb->SetState(STATE_SHADOW); + SetBackground("textures/interface/interface.png"); CreateVersionDisplay(); } @@ -235,6 +242,9 @@ bool CScreenMainMenu::EventProcess(const Event &event) m_main->ChangePhase(PHASE_SATCOM); break; + case EVENT_INTERFACE_MODS: + m_main->ChangePhase(PHASE_MOD_LIST); + default: return true; } diff --git a/src/ui/screen/screen_mod_list.cpp b/src/ui/screen/screen_mod_list.cpp new file mode 100644 index 00000000..b8558f81 --- /dev/null +++ b/src/ui/screen/screen_mod_list.cpp @@ -0,0 +1,490 @@ +/* + * This file is part of the Colobot: Gold Edition source code + * Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam + * http://epsitec.ch; http://colobot.info; http://github.com/colobot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#include "ui/screen/screen_mod_list.h" + +#include "common/config.h" + +#include "app/app.h" +#include "app/modman.h" + +#include "common/logger.h" +#include "common/restext.h" +#include "common/stringutils.h" + +#include "common/resources/resourcemanager.h" + +#include "common/system/system.h" + +#include "math/func.h" + +#include "ui/controls/button.h" +#include "ui/controls/edit.h" +#include "ui/controls/interface.h" +#include "ui/controls/label.h" +#include "ui/controls/list.h" +#include "ui/controls/window.h" + +namespace Ui +{ + +CScreenModList::CScreenModList(CMainDialog* dialog, CModManager* modManager) + : m_dialog(dialog), + m_modManager(modManager) +{ +} + +void CScreenModList::CreateInterface() +{ + CWindow* pw; + CEdit* pe; + CLabel* pl; + CButton* pb; + CList* pli; + Math::Point pos, ddim; + std::string name; + + m_changes = false; + ApplyChanges(); + + // Display the window + pos.x = 0.10f; + pos.y = 0.10f; + ddim.x = 0.80f; + ddim.y = 0.80f; + pw = m_interface->CreateWindows(pos, ddim, 12, EVENT_WINDOW5); + pw->SetClosable(true); + GetResource(RES_TEXT, RT_TITLE_MODS, name); + pw->SetName(name); + + pos.x = 0.10f; + pos.y = 0.40f; + ddim.x = 0.50f; + ddim.y = 0.50f; + pw->CreateGroup(pos, ddim, 5, EVENT_INTERFACE_GLINTl); // orange corner + pos.x = 0.40f; + pos.y = 0.10f; + ddim.x = 0.50f; + ddim.y = 0.50f; + pw->CreateGroup(pos, ddim, 4, EVENT_INTERFACE_GLINTr); // blue corner + + // Display the list of mods + pos.x = ox+sx*3; + pos.y = oy+sy*10.5f; + ddim.x = dim.x*7.5f; + ddim.y = dim.y*0.6f; + GetResource(RES_TEXT, RT_MOD_LIST, name); + pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL11, name); + pl->SetTextAlign(Gfx::TEXT_ALIGN_LEFT); + + pos.y = oy+sy*6.7f; + ddim.y = dim.y*4.5f; + ddim.x = dim.x*6.5f; + pli = pw->CreateList(pos, ddim, 0, EVENT_INTERFACE_MOD_LIST); + pli->SetState(STATE_SHADOW); + pli->SetState(STATE_EXTEND); + + UpdateModList(); + + // Displays the mod details + pos.x = ox+sx*9.5f; + pos.y = oy+sy*10.5f; + ddim.x = dim.x*7.5f; + ddim.y = dim.y*0.6f; + GetResource(RES_TEXT, RT_MOD_DETAILS, name); + pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL12, name); + pl->SetTextAlign(Gfx::TEXT_ALIGN_LEFT); + + pos.y = oy+sy*6.7f; + ddim.y = dim.y*4.5f; + ddim.x = dim.x*6.5f; + pli = pw->CreateList(pos, ddim, 0, EVENT_INTERFACE_LIST); + pli->SetState(STATE_SHADOW); + + UpdateModDetails(); + + pos = pli->GetPos(); + ddim = pli->GetDim(); + + // Displays the mod summary + pos.x = ox+sx*3; + pos.y = oy+sy*5.4f; + ddim.x = dim.x*6.5f; + ddim.y = dim.y*0.6f; + GetResource(RES_TEXT, RT_MOD_SUMMARY, name); + pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL13, name); + pl->SetTextAlign(Gfx::TEXT_ALIGN_LEFT); + + pos.x = ox+sx*3; + pos.y = oy+sy*3.6f; + ddim.x = dim.x*13.4f; + ddim.y = dim.y*1.9f; + pe = pw->CreateEdit(pos, ddim, 0, EVENT_INTERFACE_MOD_SUMMARY); + pe->SetState(STATE_SHADOW); + pe->SetMaxChar(500); + pe->SetEditCap(false); // just to see + pe->SetHighlightCap(false); + + UpdateModSummary(); + + // Apply button + pos.x = ox+sx*13.75f; + pos.y = oy+sy*2; + ddim.x = dim.x*2.0f; + ddim.y = dim.y*1; + pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_MODS_APPLY); + pb->SetState(STATE_SHADOW); + + UpdateApplyButton(); + + // Display the enable/disable button + pos.x -= dim.x*2.3f; + ddim.x = dim.x*2.0f; + pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_MOD_ENABLE_OR_DISABLE); + pb->SetState(STATE_SHADOW); + + UpdateEnableDisableButton(); + + // Display the move up button + pos.x -= dim.x*1.3f; + ddim.x = dim.x*1; + pb = pw->CreateButton(pos, ddim, 49, EVENT_INTERFACE_MOD_MOVE_UP); + pb->SetState(STATE_SHADOW); + + // Display the move down button + pos.x -= dim.x*1.3f; + pb = pw->CreateButton(pos, ddim, 50, EVENT_INTERFACE_MOD_MOVE_DOWN); + pb->SetState(STATE_SHADOW); + + UpdateUpDownButtons(); + + // Display the refresh button + pos.x -= dim.x*1.3f; + pb = pw->CreateButton(pos, ddim, 87, EVENT_INTERFACE_MODS_REFRESH); + pb->SetState(STATE_SHADOW); + + // Display the open website button + pos.x -= dim.x*1.3f; + pb = pw->CreateButton(pos, ddim, 40, EVENT_INTERFACE_WORKSHOP); + pb->SetState(STATE_SHADOW); + + // Display the open directory button + pos.x -= dim.x*1.3f; + pb = pw->CreateButton(pos, ddim, 57, EVENT_INTERFACE_MODS_DIR); + pb->SetState(STATE_SHADOW); + + // Back button + pos.x = ox+sx*3; + ddim.x = dim.x*2.3f; + pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_BACK); + pb->SetState(STATE_SHADOW); + + // Background + SetBackground("textures/interface/interface.png"); + CreateVersionDisplay(); +} + +bool CScreenModList::EventProcess(const Event &event) +{ + CWindow* pw; + CList* pl; + + const std::string workshopUrl = "https://www.moddb.com/games/colobot-gold-edition"; + const std::string modDir = CResourceManager::GetSaveLocation() + "/mods"; + + auto systemUtils = CSystemUtils::Create(); // platform-specific utils + + Mod const * mod; + + pw = static_cast(m_interface->SearchControl(EVENT_WINDOW5)); + if (pw == nullptr) return false; + + if (event.type == pw->GetEventTypeClose() || + event.type == EVENT_INTERFACE_BACK || + (event.type == EVENT_KEY_DOWN && event.GetData()->key == KEY(ESCAPE))) + { + if (m_changes) + { + m_dialog->StartQuestion(RT_DIALOG_CHANGES_QUESTION, true, true, false, + [this]() + { + ApplyChanges(); + CloseWindow(); + }, + [this]() + { + m_changes = false; // do not save changes on "No" + ApplyChanges(); + CloseWindow(); + }); + } + else + { + ApplyChanges(); + CloseWindow(); + } + return false; + } + + switch( event.type ) + { + case EVENT_INTERFACE_MOD_LIST: + pl = static_cast(pw->SearchControl(EVENT_INTERFACE_MOD_LIST)); + if (pl == nullptr) break; + m_modSelectedIndex = pl->GetSelect(); + UpdateModSummary(); + UpdateModDetails(); + UpdateEnableDisableButton(); + UpdateUpDownButtons(); + break; + + case EVENT_INTERFACE_MOD_ENABLE_OR_DISABLE: + mod = &m_modManager->GetMod(m_modSelectedIndex); + if (mod->enabled) + { + m_modManager->DisableMod(m_modSelectedIndex); + } + else + { + m_modManager->EnableMod(m_modSelectedIndex); + } + UpdateModList(); + UpdateEnableDisableButton(); + m_changes = true; + UpdateApplyButton(); + break; + + case EVENT_INTERFACE_MOD_MOVE_UP: + m_modSelectedIndex = m_modManager->MoveUp(m_modSelectedIndex); + UpdateModList(); + UpdateUpDownButtons(); + m_changes = true; + UpdateApplyButton(); + break; + + case EVENT_INTERFACE_MOD_MOVE_DOWN: + m_modSelectedIndex = m_modManager->MoveDown(m_modSelectedIndex); + UpdateModList(); + UpdateUpDownButtons(); + m_changes = true; + UpdateApplyButton(); + break; + + case EVENT_INTERFACE_MODS_REFRESH: + case EVENT_INTERFACE_MODS_APPLY: + ApplyChanges(); + // Update the whole UI + UpdateModList(); + UpdateModSummary(); + UpdateModDetails(); + UpdateEnableDisableButton(); + UpdateApplyButton(); + UpdateUpDownButtons(); + break; + + case EVENT_INTERFACE_MODS_DIR: + if (!systemUtils->OpenPath(modDir)) + { + std::string title, text; + GetResource(RES_TEXT, RT_DIALOG_OPEN_PATH_FAILED_TITLE, title); + GetResource(RES_TEXT, RT_DIALOG_OPEN_PATH_FAILED_TEXT, text); + + // Workaround for Windows: the label skips everything after the first \\ character + std::string modDirWithoutBackSlashes = modDir; + std::replace(modDirWithoutBackSlashes.begin(), modDirWithoutBackSlashes.end(), '\\', '/'); + + m_dialog->StartInformation(title, title, StrUtils::Format(text.c_str(), modDirWithoutBackSlashes.c_str())); + } + break; + + case EVENT_INTERFACE_WORKSHOP: + if (!systemUtils->OpenWebsite(workshopUrl)) + { + std::string title, text; + GetResource(RES_TEXT, RT_DIALOG_OPEN_WEBSITE_FAILED_TITLE, title); + GetResource(RES_TEXT, RT_DIALOG_OPEN_WEBSITE_FAILED_TEXT, text); + m_dialog->StartInformation(title, title, StrUtils::Format(text.c_str(), workshopUrl.c_str())); + } + break; + + default: + return true; + } + return false; +} + +void CScreenModList::ApplyChanges() +{ + if (m_changes) + { + m_changes = false; + m_modManager->SaveMods(); + } + + m_modManager->FindMods(); + m_modManager->SaveMods(); + + m_empty = (m_modManager->CountMods() == 0); + + m_modManager->UpdatePaths(); + m_modManager->ReloadResources(); + + m_modSelectedIndex = Math::Clamp(m_modSelectedIndex, static_cast(0), m_modManager->CountMods() - 1); +} + +void CScreenModList::CloseWindow() +{ + m_main->ChangePhase(PHASE_MAIN_MENU); +} + +void CScreenModList::UpdateModList() +{ + CWindow* pw = static_cast(m_interface->SearchControl(EVENT_WINDOW5)); + if (pw == nullptr) return; + + CList* pl = static_cast(pw->SearchControl(EVENT_INTERFACE_MOD_LIST)); + if (pl == nullptr) return; + + pl->Flush(); + + if (m_empty) + { + return; + } + + auto mods = m_modManager->GetMods(); + for (size_t i = 0; i < mods.size(); ++i) + { + const auto& mod = mods[i]; + pl->SetItemName(i, mod.name); + pl->SetCheck(i, mod.enabled); + pl->SetEnable(i, true); + } + + pl->SetSelect(m_modSelectedIndex); + pl->ShowSelect(false); +} + +void CScreenModList::UpdateModDetails() +{ + //TODO +} + +void CScreenModList::UpdateModSummary() +{ + //TODO +} + +void CScreenModList::UpdateEnableDisableButton() +{ + CWindow* pw = static_cast(m_interface->SearchControl(EVENT_WINDOW5)); + if (pw == nullptr) return; + + CButton* pb = static_cast(pw->SearchControl(EVENT_INTERFACE_MOD_ENABLE_OR_DISABLE)); + if (pb == nullptr) return; + + std::string buttonName{}; + + if (m_empty) + { + pb->ClearState(STATE_ENABLE); + + // Set some default name + GetResource(RES_TEXT, RT_MOD_ENABLE, buttonName); + pb->SetName(buttonName); + + return; + } + + const auto& mod = m_modManager->GetMod(m_modSelectedIndex); + + if (mod.enabled) + { + GetResource(RES_TEXT, RT_MOD_DISABLE, buttonName); + pb->SetName(buttonName); + } + else + { + GetResource(RES_TEXT, RT_MOD_ENABLE, buttonName); + pb->SetName(buttonName); + } +} + +void CScreenModList::UpdateApplyButton() +{ + CWindow* pw = static_cast(m_interface->SearchControl(EVENT_WINDOW5)); + if (pw == nullptr) return; + + CButton* pb = static_cast(pw->SearchControl(EVENT_INTERFACE_MODS_APPLY)); + if (pb == nullptr) return; + + if (m_empty) + { + pb->ClearState(STATE_ENABLE); + return; + } + + if (m_changes) + { + pb->SetState(STATE_ENABLE); + } + else + { + pb->ClearState(STATE_ENABLE); + } +} + +void CScreenModList::UpdateUpDownButtons() +{ + CWindow* pw = static_cast(m_interface->SearchControl(EVENT_WINDOW5)); + if (pw == nullptr) return; + + CButton* pb_up = static_cast(pw->SearchControl(EVENT_INTERFACE_MOD_MOVE_UP)); + if (pb_up == nullptr) return; + + CButton* pb_down = static_cast(pw->SearchControl(EVENT_INTERFACE_MOD_MOVE_DOWN)); + if (pb_down == nullptr) return; + + if (m_empty) + { + pb_up->ClearState(STATE_ENABLE); + pb_down->ClearState(STATE_ENABLE); + return; + } + + if (m_modSelectedIndex == 0) + { + pb_up->ClearState(STATE_ENABLE); + } + else + { + pb_up->SetState(STATE_ENABLE); + } + + if (m_modSelectedIndex >= m_modManager->CountMods() - 1) + { + pb_down->ClearState(STATE_ENABLE); + } + else + { + pb_down->SetState(STATE_ENABLE); + } +} + +} // namespace Ui diff --git a/src/ui/screen/screen_mod_list.h b/src/ui/screen/screen_mod_list.h new file mode 100644 index 00000000..ac039bee --- /dev/null +++ b/src/ui/screen/screen_mod_list.h @@ -0,0 +1,96 @@ +/* + * This file is part of the Colobot: Gold Edition source code + * Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam + * http://epsitec.ch; http://colobot.info; http://github.com/colobot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#pragma once + +#include "app/modman.h" + +#include "ui/screen/screen.h" + +#include "level/level_category.h" + +#include +#include + +namespace Ui +{ +class CMainDialog; + +/** + * \class CScreenModList + * \brief This class is the front-end for the \ref CModManager. + * + * \section Assumptions Assumptions + * + * It assumes the user is changing something in the mods folders while the screen is visible, + * e.g. removing them or adding more. For this reason, the mods are always reloaded after the user + * lefts the screen, possibly after asking the user if their changes should be saved. They are also reloaded + * when the user opens the screen to avoid weird situations like "the mod is no longer there but in theory + * it's still in the game's memory even if it's not visible on the list". + * + * Unsafe changes, like removing a mod which is still enabled, are a sole responsibility of the user and + * we basically can't guarantee the game will behave properly in such cases even when they happen while + * this screen is visible. + * + * \section Features UI Features + * + * The user can reorder mods with appropriate buttons and enable/disable them. To avoid reloading + * the resources after every change, the changes are not immediate. The resources are reloaded in the + * cases described above and also after using the Apply or Refresh buttons. The only technical + * difference between them is that the Refresh button is always enabled, but Apply is only enabled + * if the user made any changes in the list by using the UI. The reason is, again, to avoid dealing with + * weird situations like described above. + * + * The UI also shows the selected mod metadata like description, version, etc. + * + * There is also a button which will try to open the default web browser with the Workshop website, + * where the user can search for new mods. + * + * For convenience, also a button opening a saves/mods folder is provided. + */ +class CScreenModList : public CScreen +{ +public: + CScreenModList(CMainDialog* dialog, CModManager* modManager); + + void CreateInterface() override; + bool EventProcess(const Event &event) override; + +protected: + void ApplyChanges(); + void CloseWindow(); + + void UpdateModList(); + void UpdateModDetails(); + void UpdateModSummary(); + void UpdateEnableDisableButton(); + void UpdateApplyButton(); + void UpdateUpDownButtons(); + +protected: + Ui::CMainDialog* m_dialog; + + CModManager* m_modManager; + + size_t m_modSelectedIndex = 0; + bool m_changes = false; + bool m_empty = true; +}; + +} // namespace Ui diff --git a/src/ui/screen/screen_setup.cpp b/src/ui/screen/screen_setup.cpp index 7a83ae1e..67848640 100644 --- a/src/ui/screen/screen_setup.cpp +++ b/src/ui/screen/screen_setup.cpp @@ -83,7 +83,7 @@ void CScreenSetup::CreateInterface() ddim.y = 0.05f; pw->CreateGroup(pos, ddim, 3, EVENT_NULL); // transparent -> gray - ddim.x = 0.65f/5-0.01f; + ddim.x = 0.78f/5-0.01f; ddim.y = 0.06f; pos.x = 0.115f; pos.y = 0.76f; @@ -116,12 +116,6 @@ void CScreenSetup::CreateInterface() pb->SetState(STATE_CARD); pb->SetState(STATE_CHECK, (m_tab == PHASE_SETUPs)); - pos.x += ddim.x+0.01f; - pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_SETUPm); - pb->SetState(STATE_SHADOW); - pb->SetState(STATE_CARD); - pb->SetState(STATE_CHECK, (m_tab == PHASE_SETUPm)); - pos.x = 0.10f; ddim.x = 0.80f; pos.y = 0.34f; @@ -154,10 +148,6 @@ bool CScreenSetup::EventProcess(const Event &event) CWindow* pw = static_cast(m_interface->SearchControl(EVENT_WINDOW5)); if ( pw == nullptr ) return false; - CButton* pb = static_cast(pw->SearchControl(EVENT_INTERFACE_SETUPm)); - if ( pb == nullptr ) return false; - pb->SetState(STATE_ENABLE); - if ( event.type == pw->GetEventTypeClose() || event.type == EVENT_INTERFACE_BACK || (event.type == EVENT_KEY_DOWN && event.GetData()->key == KEY(ESCAPE)) ) @@ -189,10 +179,6 @@ bool CScreenSetup::EventProcess(const Event &event) m_main->ChangePhase(PHASE_SETUPs); return false; - case EVENT_INTERFACE_SETUPm: - m_main->ChangePhase(PHASE_SETUPm); - return false; - default: break; } @@ -202,10 +188,6 @@ bool CScreenSetup::EventProcess(const Event &event) CWindow* pw = static_cast(m_interface->SearchControl(EVENT_WINDOW5)); if ( pw == nullptr ) return false; - CButton* pb = static_cast(pw->SearchControl(EVENT_INTERFACE_SETUPm)); - if ( pb == nullptr ) return false; - pb->ClearState(STATE_ENABLE); - if ( event.type == pw->GetEventTypeClose() || event.type == EVENT_INTERFACE_BACK || (event.type == EVENT_KEY_DOWN && event.GetData()->key == KEY(ESCAPE)) ) @@ -239,9 +221,6 @@ bool CScreenSetup::EventProcess(const Event &event) m_main->ChangePhase(PHASE_SETUPss); return false; - case EVENT_INTERFACE_SETUPm: - assert(false); // should never get here - default: break; } diff --git a/src/ui/screen/screen_setup_mods.cpp b/src/ui/screen/screen_setup_mods.cpp deleted file mode 100644 index 69cd13fe..00000000 --- a/src/ui/screen/screen_setup_mods.cpp +++ /dev/null @@ -1,289 +0,0 @@ -/* - * This file is part of the Colobot: Gold Edition source code - * Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam - * http://epsitec.ch; http://colobot.info; http://github.com/colobot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see http://gnu.org/licenses - */ - -#include "ui/screen/screen_setup_mods.h" - -#include "common/config.h" - -#include "app/app.h" -#include "app/modman.h" - -#include "common/logger.h" -#include "common/restext.h" -#include "common/settings.h" -#include "common/stringutils.h" - -#include "common/resources/resourcemanager.h" - -#include "common/system/system.h" - -#include "level/parser/parser.h" - -#include "ui/controls/button.h" -#include "ui/controls/edit.h" -#include "ui/controls/interface.h" -#include "ui/controls/label.h" -#include "ui/controls/list.h" -#include "ui/controls/window.h" - -#include -#include -#include - -using namespace boost::filesystem; - -namespace Ui -{ - -CScreenSetupMods::CScreenSetupMods(CMainDialog* dialog, CModManager* modManager) - : m_dialog(dialog), - m_modManager(modManager) -{ -} - -void CScreenSetupMods::SetActive() -{ - m_tab = PHASE_SETUPm; -} - -void CScreenSetupMods::CreateInterface() -{ - CWindow* pw; - CLabel* pl; - CButton* pb; - CList* pli; - Math::Point pos, ddim; - std::string name; - - m_modManager->FindMods(); - - CScreenSetup::CreateInterface(); - pw = static_cast(m_interface->SearchControl(EVENT_WINDOW5)); - if ( pw == nullptr ) return; - - // Displays a list of unloaded mods: - pos.x = ox+sx*3; - pos.y = oy+sy*9; - ddim.x = dim.x*6; - ddim.y = dim.y*1; - GetResource(RES_TEXT, RT_MODS_UNLOADED, name); - pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL11, name); - pl->SetTextAlign(Gfx::TEXT_ALIGN_LEFT); - - pos.y = oy+sy*3.75f; - ddim.x = dim.x*6.5f; - ddim.y = dim.y*6.05f; - pli = pw->CreateList(pos, ddim, 0, EVENT_INTERFACE_MODS_UNLOADED); - pli->SetState(STATE_SHADOW); - UpdateUnloadedModList(); - - // Displays a list of loaded mods: - pos.x = ox+sx*9.5f; - pos.y = oy+sy*9; - ddim.x = dim.x*6; - ddim.y = dim.y*1; - GetResource(RES_TEXT, RT_MODS_LOADED, name); - pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL12, name); - pl->SetTextAlign(Gfx::TEXT_ALIGN_LEFT); - - pos.y = oy+sy*3.75f; - ddim.x = dim.x*6.5f; - ddim.y = dim.y*6.05f; - pli = pw->CreateList(pos, ddim, 0, EVENT_INTERFACE_MODS_LOADED); - pli->SetState(STATE_SHADOW); - UpdateLoadedModList(); - - pos = pli->GetPos(); - ddim = pli->GetDim(); - pos.x = ox+sx*8.2f; - pos.y = oy+sy*2; - ddim.x = dim.x*1; - ddim.y = dim.y*1; - pb = pw->CreateButton(pos, ddim, 40, EVENT_INTERFACE_WORKSHOP); - pb->SetState(STATE_SHADOW); - - pos.x += dim.x*1.3f; - pb = pw->CreateButton(pos, ddim, 57, EVENT_INTERFACE_MODS_DIR); - pb->SetState(STATE_SHADOW); - - pos.x += dim.x*1.3f; - ddim.x = dim.x*2.5f; - pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_LOAD); - pb->SetState(STATE_SHADOW); - pb->ClearState(STATE_ENABLE); - - pos.x += dim.x*2.8f; - pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_UNLOAD); - pb->SetState(STATE_SHADOW); - pb->ClearState(STATE_ENABLE); -} - -bool CScreenSetupMods::EventProcess(const Event &event) -{ - CWindow* pw; - CButton* pb; - CList* pl; - std::string modName; - const std::string website = "https://www.moddb.com/games/colobot-gold-edition"; - const std::string modDir = CResourceManager::GetSaveLocation() + "/mods"; - auto systemUtils = CSystemUtils::Create(); // platform-specific utils - - if (!CScreenSetup::EventProcess(event)) return false; - - pw = static_cast(m_interface->SearchControl(EVENT_WINDOW5)); - if ( pw == nullptr ) return false; - - switch (event.type) - { - case EVENT_INTERFACE_LOAD: - pl = static_cast(pw->SearchControl(EVENT_INTERFACE_MODS_UNLOADED)); - if (pl == nullptr) return false; - modName = pl->GetItemName(pl->GetSelect()); - - m_modManager->EnableMod(modName); - m_modManager->SaveMods(); - m_modManager->UpdatePaths(); - m_modManager->ReloadResources(); - - m_main->ChangePhase(PHASE_SETUPm); - break; - - case EVENT_INTERFACE_UNLOAD: - pl = static_cast(pw->SearchControl(EVENT_INTERFACE_MODS_LOADED)); - if (pl == nullptr) return false; - modName = pl->GetItemName(pl->GetSelect()); - - m_modManager->DisableMod(modName); - m_modManager->SaveMods(); - m_modManager->UpdatePaths(); - m_modManager->ReloadResources(); - - m_main->ChangePhase(PHASE_SETUPm); - break; - - case EVENT_INTERFACE_MODS_UNLOADED: - pl = static_cast(pw->SearchControl(EVENT_INTERFACE_MODS_LOADED)); - if ( pl == nullptr ) break; - - pb = static_cast(pw->SearchControl(EVENT_INTERFACE_UNLOAD)); - if ( pb == nullptr ) break; - pl->SetSelect(-1); - pb->ClearState(STATE_ENABLE); - - pb = static_cast(pw->SearchControl(EVENT_INTERFACE_LOAD)); - if ( pb == nullptr ) break; - pb->SetState(STATE_ENABLE); - break; - - case EVENT_INTERFACE_MODS_LOADED: - pl = static_cast(pw->SearchControl(EVENT_INTERFACE_MODS_UNLOADED)); - if ( pl == nullptr ) break; - - pb = static_cast(pw->SearchControl(EVENT_INTERFACE_LOAD)); - if ( pb == nullptr ) break; - pl->SetSelect(-1); - pb->ClearState(STATE_ENABLE); - - pb = static_cast(pw->SearchControl(EVENT_INTERFACE_UNLOAD)); - if ( pb == nullptr ) break; - pb->SetState(STATE_ENABLE); - break; - - case EVENT_INTERFACE_MODS_DIR: - if (!systemUtils->OpenPath(modDir)) - { - std::string title, text; - GetResource(RES_TEXT, RT_DIALOG_OPEN_PATH_FAILED_TITLE, title); - GetResource(RES_TEXT, RT_DIALOG_OPEN_PATH_FAILED_TEXT, text); - - // Workaround for Windows: the label skips everything after the first \\ character - std::string modDirWithoutBackSlashes = modDir; - std::replace(modDirWithoutBackSlashes.begin(), modDirWithoutBackSlashes.end(), '\\', '/'); - - m_dialog->StartInformation(title, title, StrUtils::Format(text.c_str(), modDirWithoutBackSlashes.c_str())); - } - break; - - case EVENT_INTERFACE_WORKSHOP: - if (!systemUtils->OpenWebsite(website)) - { - std::string title, text; - GetResource(RES_TEXT, RT_DIALOG_OPEN_WEBSITE_FAILED_TITLE, title); - GetResource(RES_TEXT, RT_DIALOG_OPEN_WEBSITE_FAILED_TEXT, text); - m_dialog->StartInformation(title, title, StrUtils::Format(text.c_str(), website.c_str())); - } - break; - - default: - return true; - } - return false; -} - -void CScreenSetupMods::UpdateUnloadedModList() -{ - CWindow* pw; - CList* pl; - int i = 0; - directory_iterator end_itr; - - pw = static_cast(m_interface->SearchControl(EVENT_WINDOW5)); - if ( pw == nullptr ) return; - - pl = static_cast(pw->SearchControl(EVENT_INTERFACE_MODS_UNLOADED)); - if ( pl == nullptr ) return; - pl->Flush(); - - for (const auto& mod : m_modManager->GetMods()) - { - if (!mod.enabled) - { - pl->SetItemName(i++, mod.name); - } - } - - pl->ShowSelect(false); // shows the selected columns -} - -void CScreenSetupMods::UpdateLoadedModList() -{ - CWindow* pw; - CList* pl; - int i = 0; - directory_iterator end_itr; - - pw = static_cast(m_interface->SearchControl(EVENT_WINDOW5)); - if ( pw == nullptr ) return; - - pl = static_cast(pw->SearchControl(EVENT_INTERFACE_MODS_LOADED)); - if ( pl == nullptr ) return; - pl->Flush(); - - for (const auto& mod : m_modManager->GetMods()) - { - if (mod.enabled) - { - pl->SetItemName(i++, mod.name); - } - } - - pl->ShowSelect(false); // shows the selected columns -} - -} // namespace Ui diff --git a/src/ui/screen/screen_setup_mods.h b/src/ui/screen/screen_setup_mods.h deleted file mode 100644 index 9098d7d7..00000000 --- a/src/ui/screen/screen_setup_mods.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * This file is part of the Colobot: Gold Edition source code - * Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam - * http://epsitec.ch; http://colobot.info; http://github.com/colobot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see http://gnu.org/licenses - */ - -#pragma once - -#include "ui/maindialog.h" - -#include "ui/screen/screen_setup.h" - -#include - -class CModManager; - -namespace Ui -{ - -class CScreenSetupMods : public CScreenSetup -{ -public: - CScreenSetupMods(CMainDialog* dialog, CModManager* modManager); - void SetActive() override; - - void CreateInterface() override; - bool EventProcess(const Event &event) override; - -protected: - void UpdateUnloadedModList(); - void UpdateLoadedModList(); - -protected: - CMainDialog* m_dialog; - - CModManager* m_modManager; -}; - -} // namespace Ui From eac74c23ec743fea825041f869f0b25f33b2826c Mon Sep 17 00:00:00 2001 From: MrSimbax Date: Tue, 21 Jul 2020 20:39:00 +0200 Subject: [PATCH 37/98] Fix linter issues --- src/app/modman.cpp | 1 - src/ui/screen/screen_mod_list.h | 5 ----- 2 files changed, 6 deletions(-) diff --git a/src/app/modman.cpp b/src/app/modman.cpp index cf552641..06c2b430 100644 --- a/src/app/modman.cpp +++ b/src/app/modman.cpp @@ -33,7 +33,6 @@ #include #include #include -#include "modman.h" using namespace boost::filesystem; diff --git a/src/ui/screen/screen_mod_list.h b/src/ui/screen/screen_mod_list.h index ac039bee..e75d4baa 100644 --- a/src/ui/screen/screen_mod_list.h +++ b/src/ui/screen/screen_mod_list.h @@ -23,11 +23,6 @@ #include "ui/screen/screen.h" -#include "level/level_category.h" - -#include -#include - namespace Ui { class CMainDialog; From 5112bf86df9daff0ea5e7b9e4773b80f4e40582a Mon Sep 17 00:00:00 2001 From: MrSimbax Date: Tue, 21 Jul 2020 21:11:08 +0200 Subject: [PATCH 38/98] Fix linter issues --- src/graphics/opengl/gl21device.cpp | 3 ++- src/graphics/opengl/gl33device.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/graphics/opengl/gl21device.cpp b/src/graphics/opengl/gl21device.cpp index 51bb2128..e0782271 100644 --- a/src/graphics/opengl/gl21device.cpp +++ b/src/graphics/opengl/gl21device.cpp @@ -666,7 +666,8 @@ void CGL21Device::SetTransform(TransformType type, const Math::Matrix &matrix) glUniformMatrix4fv(m_uniforms[m_mode].viewMatrix, 1, GL_FALSE, m_viewMat.Array()); - if (m_uniforms[m_mode].cameraPosition >= 0) { + if (m_uniforms[m_mode].cameraPosition >= 0) + { cameraPosition.LoadZero(); cameraPosition = MatrixVectorMultiply(m_viewMat.Inverse(), cameraPosition); glUniform3fv(m_uniforms[m_mode].cameraPosition, 1, cameraPosition.Array()); diff --git a/src/graphics/opengl/gl33device.cpp b/src/graphics/opengl/gl33device.cpp index cd9c0343..2ca1aa4f 100644 --- a/src/graphics/opengl/gl33device.cpp +++ b/src/graphics/opengl/gl33device.cpp @@ -671,7 +671,8 @@ void CGL33Device::SetTransform(TransformType type, const Math::Matrix &matrix) glUniformMatrix4fv(m_uni->viewMatrix, 1, GL_FALSE, m_viewMat.Array()); - if (m_uni->cameraPosition >= 0) { + if (m_uni->cameraPosition >= 0) + { cameraPosition.LoadZero(); cameraPosition = MatrixVectorMultiply(m_viewMat.Inverse(), cameraPosition); glUniform3fv(m_uni->cameraPosition, 1, cameraPosition.Array()); From a5c718701779096d214a9afca50206eb474da00a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Przyby=C5=82?= Date: Wed, 22 Jul 2020 00:37:37 +0200 Subject: [PATCH 39/98] Fix crashes on SatCom in Moon missions (#1334) --- src/graphics/engine/text.cpp | 38 +++++++++++++++++++----------------- src/graphics/engine/text.h | 2 ++ 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/graphics/engine/text.cpp b/src/graphics/engine/text.cpp index 484a7374..9ff42bb6 100644 --- a/src/graphics/engine/text.cpp +++ b/src/graphics/engine/text.cpp @@ -430,7 +430,7 @@ float CText::GetStringWidth(const std::string &text, UTF8Char ch; - int len = StrUtils::Utf8CharSizeAt(text, index); + int len = GetCharSizeAt(font, text, index); if (len >= 1) ch.c1 = text[index]; if (len >= 2) @@ -565,7 +565,7 @@ int CText::Justify(const std::string &text, std::vector::iterator UTF8Char ch; - int len = StrUtils::Utf8CharSizeAt(text, index); + int len = GetCharSizeAt(font, text, index); if (len >= 1) ch.c1 = text[index]; if (len >= 2) @@ -606,7 +606,7 @@ int CText::Justify(const std::string &text, FontType font, float size, float wid { UTF8Char ch; - int len = StrUtils::Utf8CharSizeAt(text, index); + int len = GetCharSizeAt(font, text, index); if (len >= 1) ch.c1 = text[index]; if (len >= 2) @@ -648,12 +648,9 @@ int CText::Detect(const std::string &text, std::vector::iterator f if (format + fmtIndex != end) font = static_cast(*(format + fmtIndex) & FONT_MASK_FONT); - // TODO: if (font == FONT_BUTTON) - //if (font == FONT_BUTTON) continue; - UTF8Char ch; - int len = StrUtils::Utf8CharSizeAt(text, index); + int len = GetCharSizeAt(font, text, index); if (len >= 1) ch.c1 = text[index]; if (len >= 2) @@ -686,7 +683,7 @@ int CText::Detect(const std::string &text, FontType font, float size, float offs { UTF8Char ch; - int len = StrUtils::Utf8CharSizeAt(text, index); + int len = GetCharSizeAt(font, text, index); if (len >= 1) ch.c1 = text[index]; if (len >= 2) @@ -898,16 +895,7 @@ void CText::StringToUTFCharList(const std::string &text, std::vector & if (format + index != end) font = static_cast(*(format + index) & FONT_MASK_FONT); - int len; - - if(font == FONT_BUTTON) - { - len = 1; - } - else - { - len = StrUtils::Utf8CharSizeAt(text, index); - } + int len = GetCharSizeAt(font, text, index); if (len >= 1) ch.c1 = text[index]; @@ -922,6 +910,20 @@ void CText::StringToUTFCharList(const std::string &text, std::vector & } } +int CText::GetCharSizeAt(Gfx::FontType font, const std::string& text, unsigned int index) const +{ + int len = 0; + if (font == FONT_BUTTON) + { + len = 1; + } + else + { + len = StrUtils::Utf8CharSizeAt(text, index); + } + return len; +} + void CText::DrawString(const std::string &text, FontType font, float size, Math::IntPoint pos, int width, int eol, Color color) { diff --git a/src/graphics/engine/text.h b/src/graphics/engine/text.h index 3a5bff88..d0abbcee 100644 --- a/src/graphics/engine/text.h +++ b/src/graphics/engine/text.h @@ -337,6 +337,8 @@ protected: void StringToUTFCharList(const std::string &text, std::vector &chars); void StringToUTFCharList(const std::string &text, std::vector &chars, std::vector::iterator format, std::vector::iterator end); + int GetCharSizeAt(Gfx::FontType font, const std::string& text, unsigned int index) const; + protected: CEngine* m_engine; CDevice* m_device; From f57da76ae8d71e4e70225af9b89db6d4852ec303 Mon Sep 17 00:00:00 2001 From: MrSimbax Date: Wed, 22 Jul 2020 16:18:18 +0200 Subject: [PATCH 40/98] Add handling of mods manifests Also add Polish translations for mod manager related strings. --- CMakeLists.txt | 2 +- po/colobot.pot | 45 ++++++++---- po/cs.po | 17 +++++ po/de.po | 17 +++++ po/fr.po | 17 +++++ po/pl.po | 46 +++++++----- po/pt.po | 17 +++++ po/ru.po | 17 +++++ src/CMakeLists.txt | 2 + src/app/app.cpp | 4 +- src/app/moddata.cpp | 114 +++++++++++++++++++++++++++++ src/app/moddata.h | 36 ++++++++++ src/app/modman.cpp | 27 ++++++- src/app/modman.h | 35 ++++----- src/app/pathman.cpp | 4 +- src/common/restext.cpp | 17 +++-- src/common/restext.h | 15 ++-- src/ui/screen/screen_mod_list.cpp | 115 ++++++++++++++++++++++++++---- src/ui/screen/screen_mod_list.h | 5 +- 19 files changed, 468 insertions(+), 84 deletions(-) create mode 100644 src/app/moddata.cpp create mode 100644 src/app/moddata.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 94c3a574..90843488 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -189,7 +189,7 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") set(NORMAL_CXX_FLAGS "/wd\"4244\" /wd\"4309\" /wd\"4800\" /wd\"4996\" /wd\"4351\" /EHsc") # disable some useless warnings if(MSVC_STATIC) set(RELEASE_CXX_FLAGS "/MT /Ox") - set(DEBUG_CXX_FLAGS "/MTd /ZI") + set(DEBUG_CXX_FLAGS "/MTd /Od /ZI") else(MSVC_STATIC) set(RELEASE_CXX_FLAGS "/MD /Ox") set(DEBUG_CXX_FLAGS "/MDd /Od /ZI") diff --git a/po/colobot.pot b/po/colobot.pot index 53bfda71..b459a8f3 100644 --- a/po/colobot.pot +++ b/po/colobot.pot @@ -123,21 +123,6 @@ msgstr "" msgid "2) Then press the key you want to use instead." msgstr "" -msgid "Mods:" -msgstr "" - -msgid "Information:" -msgstr "" - -msgid "Description:" -msgstr "" - -msgid "Enable\\Enable the selected mod" -msgstr "" - -msgid "Disable\\Disable the selected mod" -msgstr "" - msgid "Face type:" msgstr "" @@ -315,6 +300,36 @@ msgstr "" msgid "%s: %d pts" msgstr "" +msgid "Mods:" +msgstr "" + +msgid "Information:" +msgstr "" + +msgid "Description:" +msgstr "" + +msgid "Enable\\Enable the selected mod" +msgstr "" + +msgid "Disable\\Disable the selected mod" +msgstr "" + +msgid "Unknown author" +msgstr "" + +msgid "by" +msgstr "" + +msgid "Version" +msgstr "" + +msgid "Website" +msgstr "" + +msgid "No description." +msgstr "" + msgid "Code battle" msgstr "" diff --git a/po/cs.po b/po/cs.po index 532510ea..6fb3aa3e 100644 --- a/po/cs.po +++ b/po/cs.po @@ -988,6 +988,10 @@ msgstr "Další objekt\\Vybere následující objekt" msgid "No" msgstr "Ne" +#, fuzzy +msgid "No description." +msgstr "Rozlišení:" + msgid "No energy in the subsoil" msgstr "Pod povrchem není zdroj energie" @@ -1735,6 +1739,10 @@ msgstr "Jednotka" msgid "Unknown Object" msgstr "Neznámý objekt" +#, fuzzy +msgid "Unknown author" +msgstr "Neznámá funkce" + msgid "Unknown command" msgstr "Neznámý příkaz" @@ -1771,6 +1779,9 @@ msgstr "Proměnná nebyla nastavena" msgid "Vault" msgstr "Trezor" +msgid "Version" +msgstr "" + msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency" msgstr "" @@ -1789,6 +1800,9 @@ msgstr "Vosa byla smrtelně raněna" msgid "Waste" msgstr "Odpad" +msgid "Website" +msgstr "" + msgid "Wheeled builder" msgstr "" @@ -1975,6 +1989,9 @@ msgstr "\\Fialové vlajky" msgid "\\Yellow flags" msgstr "\\Žluté vlajky" +msgid "by" +msgstr "" + msgid "colobot.info" msgstr "colobot.info" diff --git a/po/de.po b/po/de.po index 15f4c336..23b581f4 100644 --- a/po/de.po +++ b/po/de.po @@ -1004,6 +1004,10 @@ msgstr "Nächstes auswählen\\Nächstes Objekt auswählen" msgid "No" msgstr "Nein" +#, fuzzy +msgid "No description." +msgstr "Auflösung:" + msgid "No energy in the subsoil" msgstr "Kein unterirdisches Energievorkommen" @@ -1752,6 +1756,10 @@ msgstr "Einheit" msgid "Unknown Object" msgstr "Das Objekt existiert nicht" +#, fuzzy +msgid "Unknown author" +msgstr "Unbekannte Funktion" + msgid "Unknown command" msgstr "Befehl unbekannt" @@ -1788,6 +1796,9 @@ msgstr "Der Wert dieser Variable wurde nicht definiert" msgid "Vault" msgstr "Bunker" +msgid "Version" +msgstr "" + msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency" msgstr "" @@ -1806,6 +1817,9 @@ msgstr "Wespe tödlich verwundet" msgid "Waste" msgstr "Abfall" +msgid "Website" +msgstr "" + msgid "Wheeled builder" msgstr "" @@ -1990,6 +2004,9 @@ msgstr "\\Violette Fahne" msgid "\\Yellow flags" msgstr "\\Gelbe Fahne" +msgid "by" +msgstr "" + msgid "colobot.info" msgstr "colobot.info" diff --git a/po/fr.po b/po/fr.po index 1b07f1fe..6c13748d 100644 --- a/po/fr.po +++ b/po/fr.po @@ -1006,6 +1006,10 @@ msgstr "Sélectionner l'objet suivant\\Sélectionner l'objet suivant" msgid "No" msgstr "Non" +#, fuzzy +msgid "No description." +msgstr "Résolutions :" + msgid "No energy in the subsoil" msgstr "Pas d'énergie en sous-sol" @@ -1754,6 +1758,10 @@ msgstr "Unité" msgid "Unknown Object" msgstr "Objet inconnu" +#, fuzzy +msgid "Unknown author" +msgstr "Routine inconnue" + msgid "Unknown command" msgstr "Commande inconnue" @@ -1790,6 +1798,9 @@ msgstr "Variable non initialisée" msgid "Vault" msgstr "Coffre-fort" +msgid "Version" +msgstr "" + msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency" msgstr "Synchronisation verticale :\\Réduit la fréquence d'images par seconde à afficher." @@ -1808,6 +1819,9 @@ msgstr "Guêpe mortellement touchée" msgid "Waste" msgstr "Déchet" +msgid "Website" +msgstr "" + msgid "Wheeled builder" msgstr "" @@ -1992,6 +2006,9 @@ msgstr "\\Drapeaux violets" msgid "\\Yellow flags" msgstr "\\Drapeaux jaunes" +msgid "by" +msgstr "" + msgid "colobot.info" msgstr "colobot.info" diff --git a/po/pl.po b/po/pl.po index 251de7fe..9f00c679 100644 --- a/po/pl.po +++ b/po/pl.po @@ -125,7 +125,7 @@ msgid "Apply changes\\Activates the changed settings" msgstr "Zastosuj zmiany\\Aktywuje zmienione ustawienia" msgid "Apply\\Apply the current mod configuration" -msgstr "" +msgstr "Zastosuj\\Zastosuj obecną konfigurację modów" msgid "Appropriate constructor missing" msgstr "Brak odpowiedniego konstruktora" @@ -481,9 +481,8 @@ msgstr "Kopalnia" msgid "Descend\\Reduces the power of the jet" msgstr "W dół\\Zmniejsza moc silnika" -#, fuzzy msgid "Description:" -msgstr "Rozdzielczość:" +msgstr "Opis:" msgid "Destroy" msgstr "Zniszcz" @@ -497,9 +496,8 @@ msgstr "Destroyer" msgid "Device\\Driver and resolution settings" msgstr "Urządzenie\\Ustawienia sterownika i rozdzielczości" -#, fuzzy msgid "Disable\\Disable the selected mod" -msgstr "Usuń\\Usuwa zaznaczony plik" +msgstr "Wyłącz\\Wyłącza zaznaczonego moda" msgid "Dividing by zero" msgstr "Dzielenie przez zero" @@ -518,7 +516,7 @@ msgid "Down (\\key gdown;)" msgstr "Dół (\\key gdown;)" msgid "Down\\Move the selected mod down so it's loaded later (mods may overwrite files from the mods above them)" -msgstr "" +msgstr "W dół\\Przenieś zaznaczonego moda w dół, aby był załadowany później (mody mogą nadpisywać pliki modów wyżej)" msgid "Drawer bot" msgstr "Robot rysownik" @@ -547,9 +545,8 @@ msgstr "Jajo" msgid "Empty character constant" msgstr "" -#, fuzzy msgid "Enable\\Enable the selected mod" -msgstr "Wczytaj\\Wczytuje zaznaczoną misję" +msgstr "Włącz\\Włącza zaznaczonego moda" msgid "End of block missing" msgstr "Brak końca bloku" @@ -778,7 +775,7 @@ msgid "Information exchange post" msgstr "Stacja przekaźnikowa informacji" msgid "Information:" -msgstr "" +msgstr "Informacje:" msgid "Instruction \"break\" outside a loop" msgstr "Polecenie \"break\" na zewnątrz pętli" @@ -931,13 +928,13 @@ msgid "Missions\\Select mission" msgstr "Misje\\Wybierz misję" msgid "Mods" -msgstr "" +msgstr "Mody" msgid "Mods:" -msgstr "" +msgstr "Mody:" msgid "Mods\\Mod manager" -msgstr "" +msgstr "Mody\\Zarządzanie modami" msgid "Mouse inversion X\\Inversion of the scrolling direction on the X axis" msgstr "Odwrócenie myszy X\\Odwrócenie kierunków przewijania w poziomie" @@ -987,6 +984,9 @@ msgstr "Następny obiekt\\Zaznacza następny obiekt" msgid "No" msgstr "Nie" +msgid "No description." +msgstr "Brak opisu." + msgid "No energy in the subsoil" msgstr "Brak energii w ziemi" @@ -1108,7 +1108,7 @@ msgid "Open (Ctrl+O)" msgstr "Otwórz (Ctrl+O)" msgid "Open Directory\\Open the mods directory" -msgstr "" +msgstr "Otwórz katalog\\Otwórz katalog z modami" msgid "Opening brace missing" msgstr "Brak klamry otwierającej" @@ -1321,7 +1321,7 @@ msgid "Reflections on the buttons \\Shiny buttons" msgstr "Odbicia na przyciskach \\Świecące przyciski" msgid "Refresh\\Refresh the list of currently installed mods" -msgstr "" +msgstr "Odśwież\\Odśwież listę obecnie zainstalowanych modów" msgid "Remains of Apollo mission" msgstr "Pozostałości z misji Apollo" @@ -1608,7 +1608,7 @@ msgid "The types of the two operands are incompatible" msgstr "Niezgodne typy operatorów" msgid "There are unsaved changes. Do you want to save them before leaving?" -msgstr "" +msgstr "Są niezapisane zmiany. Czy chcesz je zapisać przed wyjściem?" msgid "This class already exists" msgstr "Taka klasa już istnieje" @@ -1734,6 +1734,9 @@ msgstr "Jednostka" msgid "Unknown Object" msgstr "Obiekt nieznany" +msgid "Unknown author" +msgstr "Nieznany autor" + msgid "Unknown command" msgstr "Nieznane polecenie" @@ -1747,7 +1750,7 @@ msgid "Up (\\key gup;)" msgstr "Góra (\\key gup;)" msgid "Up\\Move the selected mod up so it's loaded sooner (mods may overwrite files from the mods above them)" -msgstr "" +msgstr "W górę\\Przenieś zaznaczonego moda w górę, aby był załadowany wcześniej (mody mogą nadpisywać pliki modów wyżej)" msgid "Uranium deposit (site for derrick)" msgstr "Złoże uranu (miejsce na kopalnię)" @@ -1770,6 +1773,9 @@ msgstr "Zmienna nie została zainicjalizowana" msgid "Vault" msgstr "Skrytka" +msgid "Version" +msgstr "Wersja" + msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency" msgstr "Synchronizacja pionowa\\Ogranicza ilość klatek na sekundę do wartości odświeżania ekranu" @@ -1788,6 +1794,9 @@ msgstr "Osa śmiertelnie raniona" msgid "Waste" msgstr "Odpady" +msgid "Website" +msgstr "Strona internetowa" + msgid "Wheeled builder" msgstr "" @@ -1822,7 +1831,7 @@ msgid "Withdraw shield (\\key action;)" msgstr "Wyłącz osłonę (\\key action;)" msgid "Workshop\\Open the workshop to search for mods" -msgstr "" +msgstr "Warsztat\\Otwórz warsztat, aby poszukać modów" msgid "Worm" msgstr "Robal" @@ -1974,6 +1983,9 @@ msgstr "\\Fioletowe flagi" msgid "\\Yellow flags" msgstr "\\Żółte flagi" +msgid "by" +msgstr "autorstwa" + msgid "colobot.info" msgstr "colobot.info" diff --git a/po/pt.po b/po/pt.po index aed2d681..05285903 100644 --- a/po/pt.po +++ b/po/pt.po @@ -1001,6 +1001,10 @@ msgstr "Próximo objeto\\Selecionar o próximo objeto" msgid "No" msgstr "Não" +#, fuzzy +msgid "No description." +msgstr "Resolução:" + msgid "No energy in the subsoil" msgstr "Nenhuma energia no subsolo" @@ -1749,6 +1753,10 @@ msgstr "Unidade" msgid "Unknown Object" msgstr "Objeto desconhecido" +#, fuzzy +msgid "Unknown author" +msgstr "Função desconhecida" + msgid "Unknown command" msgstr "Comando desconhecido" @@ -1785,6 +1793,9 @@ msgstr "Variável não inicializada" msgid "Vault" msgstr "Cofre" +msgid "Version" +msgstr "" + msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency" msgstr "" @@ -1803,6 +1814,9 @@ msgstr "Vespa fatalmente ferida" msgid "Waste" msgstr "Desperdício" +msgid "Website" +msgstr "" + msgid "Wheeled builder" msgstr "" @@ -1987,6 +2001,9 @@ msgstr "\\Bandeiras violetas" msgid "\\Yellow flags" msgstr "\\Bandeiras amarelas" +msgid "by" +msgstr "" + msgid "colobot.info" msgstr "colobot.info" diff --git a/po/ru.po b/po/ru.po index d450ccf4..2a4dccaa 100644 --- a/po/ru.po +++ b/po/ru.po @@ -1012,6 +1012,10 @@ msgstr "Следующий объект\\Выбор следующего объ msgid "No" msgstr "Нет" +#, fuzzy +msgid "No description." +msgstr "Разрешение:" + msgid "No energy in the subsoil" msgstr "Под землей нет запасов энергии" @@ -1765,6 +1769,10 @@ msgstr "Юнит" msgid "Unknown Object" msgstr "Неизвестный объект" +#, fuzzy +msgid "Unknown author" +msgstr "Неизвестная функция" + msgid "Unknown command" msgstr "Неизвестная команда" @@ -1801,6 +1809,9 @@ msgstr "Переменная не инициализирована" msgid "Vault" msgstr "Хранилище" +msgid "Version" +msgstr "" + msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency" msgstr "" @@ -1819,6 +1830,9 @@ msgstr "Оса смертельно ранена" msgid "Waste" msgstr "Мусор" +msgid "Website" +msgstr "" + msgid "Wheeled builder" msgstr "" @@ -2003,6 +2017,9 @@ msgstr "\\Фиолетовый флаг" msgid "\\Yellow flags" msgstr "\\Желтый флаг" +msgid "by" +msgstr "" + msgid "colobot.info" msgstr "colobot.info" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index df752615..f00e77a6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -145,6 +145,8 @@ set(BASE_SOURCES app/controller.h app/input.cpp app/input.h + app/moddata.cpp + app/moddata.h app/modman.cpp app/modman.h app/pathman.cpp diff --git a/src/app/app.cpp b/src/app/app.cpp index 54a14d07..72c2c2e1 100644 --- a/src/app/app.cpp +++ b/src/app/app.cpp @@ -520,9 +520,7 @@ bool CApplication::Create() GetLogger()->Warn("Config could not be loaded. Default values will be used!\n"); } - m_modManager->FindMods(); - m_modManager->SaveMods(); - m_modManager->UpdatePaths(); + m_modManager->Init(); // Create the sound instance. #ifdef OPENAL_SOUND diff --git a/src/app/moddata.cpp b/src/app/moddata.cpp new file mode 100644 index 00000000..3ff716d7 --- /dev/null +++ b/src/app/moddata.cpp @@ -0,0 +1,114 @@ +/* + * This file is part of the Colobot: Gold Edition source code + * Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam + * http://epsitec.ch; http://colobot.info; http://github.com/colobot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#include "app/moddata.h" + +#include "common/logger.h" +#include "common/make_unique.h" + +#include "common/resources/resourcemanager.h" +#include "common/resources/inputstream.h" + +#include +#include +#include + +namespace pt = boost::property_tree; + +boost::optional LoadManifest(const std::string& path, bool loaded = false); +std::string GetStringProperty(const pt::ptree& manifest, const std::string& key); +std::unordered_map GetLanguageStringProperty(const pt::ptree& manifest, const std::string& key); + +ModData LoadModData(const std::string& path, bool loaded) +{ + ModData modData{}; + + auto manifestOptional = LoadManifest(path); + if (!manifestOptional.has_value()) + { + return modData; + } + auto manifest = manifestOptional.get(); + + modData.displayName = GetLanguageStringProperty(manifest, "DisplayName"); + modData.version = GetStringProperty(manifest, "Version"); + modData.author = GetStringProperty(manifest, "Author"); + modData.website = GetStringProperty(manifest, "Website"); + modData.summary = GetLanguageStringProperty(manifest, "Summary"); + + return modData; +} + +boost::optional LoadManifest(const std::string& path, bool loaded) +{ + try + { + auto inputStream = MakeUnique("manifest.json"); + if (!inputStream->is_open()) + { + GetLogger()->Error("Error on parsing the manifest file %s: failed to open file\n"); + return {}; + } + + pt::ptree manifest{}; + boost::property_tree::json_parser::read_json(*inputStream, manifest); + + return manifest; + } + catch (std::exception& e) + { + GetLogger()->Warn("Error on parsing the manifest file %s: %s\n", path.c_str(), e.what()); + return {}; + } + return {}; +} + +std::string GetStringProperty(const pt::ptree& manifest, const std::string& key) +{ + auto prop = manifest.get_optional(key); + if (prop.has_value()) + { + return prop.get(); + } + return {}; +} + +std::unordered_map GetLanguageStringProperty(const pt::ptree& manifest, const std::string& key) +{ + std::unordered_map ret; + auto prop = manifest.get_child_optional(key); + if (prop.has_value()) + { + for (const auto& child : prop.get()) + { + Language language = LANGUAGE_ENGLISH; + std::string strLanguage = child.first.data(); + if (!ParseLanguage(strLanguage, language)) + { + GetLogger()->Warn("Error on parsing the manifest file: %s language %s is not a valid language\n", key.c_str(), strLanguage.c_str()); + continue; + } + else + { + ret.insert(std::make_pair(language, child.second.data())); + } + } + } + return ret; +} diff --git a/src/app/moddata.h b/src/app/moddata.h new file mode 100644 index 00000000..90f3887c --- /dev/null +++ b/src/app/moddata.h @@ -0,0 +1,36 @@ +/* +* This file is part of the Colobot: Gold Edition source code +* Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam +* http://epsitec.ch; http://colobot.info; http://github.com/colobot +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see http://gnu.org/licenses +*/ + +#pragma once + +#include "common/language.h" + +#include + +struct ModData +{ + std::unordered_map displayName{}; + std::string author{}; + std::string version{}; + std::string website{}; + std::unordered_map summary{}; +}; + +//! Loads the metadata for a mod in the given path. +ModData LoadModData(const std::string& path, bool loaded = false); diff --git a/src/app/modman.cpp b/src/app/modman.cpp index 06c2b430..a8dcf7d3 100644 --- a/src/app/modman.cpp +++ b/src/app/modman.cpp @@ -42,10 +42,8 @@ CModManager::CModManager(CApplication* app, CPathManager* pathManager) { } -void CModManager::FindMods() +void CModManager::Init() { - m_mods.clear(); - // Load names from the config file std::vector savedModNames; GetConfigFile().GetArrayProperty("Mods", "Names", savedModNames); @@ -102,6 +100,29 @@ void CModManager::FindMods() mod.path = newMod.second; m_mods.push_back(mod); } + + SaveMods(); + + // Load the metadata for each mod + for (auto& mod : m_mods) + { + m_pathManager->AddMod(mod.path); + mod.data = LoadModData(mod.path); + m_pathManager->RemoveMod(mod.path); + } + + UpdatePaths(); +} + +void CModManager::ReloadMods() +{ + m_mods.clear(); + m_pathManager->RemoveAllMods(); + + Init(); + + // Apply the configuration + ReloadResources(); } void CModManager::EnableMod(size_t i) diff --git a/src/app/modman.h b/src/app/modman.h index 984d54ea..a937ec20 100644 --- a/src/app/modman.h +++ b/src/app/modman.h @@ -19,13 +19,12 @@ #pragma once -#include "ui/maindialog.h" - -#include "ui/screen/screen_setup.h" +#include "app/moddata.h" #include #include +class CApplication; class CPathManager; struct Mod @@ -33,7 +32,7 @@ struct Mod std::string name{}; std::string path{}; bool enabled = false; - //TODO: add metadata for UI + ModData data{}; }; /** @@ -43,20 +42,22 @@ struct Mod * The order matters since the order in which files are loaded matters, * because some files can be overwritten. * - * The list can be kept in the config file with the \ref SaveMods function. - * - * The changes in the list do not immediately apply. - * Separate calls to \ref UpdatePaths and \ref ReloadResources, probably in this order, - * need to be done for the changes to apply. + * The changes in the list do not immediately apply + * and will be lost after the \ref ReloadMods call if they were not + * saved beforehand with \ref SaveMods. * + * The changes are also lost to mods which are no longer found in the search paths. */ class CModManager { public: CModManager(CApplication* app, CPathManager* pathManager); + //! Loads mods without resource reloading; should be called only once after creation + void Init(); + //! Finds all the mods along with their metadata - void FindMods(); + void ReloadMods(); //! Removes a mod from the list of loaded mods void EnableMod(size_t i); @@ -70,15 +71,9 @@ public: //! Moves the selected mod down in the list so that it's loaded later than others, returns the new index size_t MoveDown(size_t i); - //! Reloads application resources so the enabled mods are applied - void ReloadResources(); - //! Saves the current configuration of mods to the config file void SaveMods(); - //! Updates the paths in Path Manager according to the current mod configuration - void UpdatePaths(); - //! Number of mods loaded size_t CountMods() const; @@ -88,10 +83,16 @@ public: //! Returns the list of mods const std::vector& GetMods() const; +private: + //! Updates the paths in Path Manager according to the current mod configuration + void UpdatePaths(); + + //! Reloads application resources so the enabled mods are applied + void ReloadResources(); + private: CApplication* m_app; CPathManager* m_pathManager; - //TODO: better data structure? std::vector m_mods; }; diff --git a/src/app/pathman.cpp b/src/app/pathman.cpp index 080c9b70..e353ec1a 100644 --- a/src/app/pathman.cpp +++ b/src/app/pathman.cpp @@ -71,14 +71,14 @@ void CPathManager::AddModSearchDir(const std::string &modSearchDirPath) void CPathManager::AddMod(const std::string &modPath) { - GetLogger()->Info("Loading mod: '%s'\n", modPath.c_str()); + GetLogger()->Debug("Adding mod: '%s'\n", modPath.c_str()); CResourceManager::AddLocation(modPath, true); m_mods.push_back(modPath); } void CPathManager::RemoveMod(const std::string &modPath) { - GetLogger()->Info("Unloading mod: '%s'\n", modPath.c_str()); + GetLogger()->Debug("Removing mod: '%s'\n", modPath.c_str()); CResourceManager::RemoveLocation(modPath); auto it = std::find(m_mods.cbegin(), m_mods.cend(), modPath); if (it != m_mods.cend()) diff --git a/src/common/restext.cpp b/src/common/restext.cpp index 664b8ac3..294aa1eb 100644 --- a/src/common/restext.cpp +++ b/src/common/restext.cpp @@ -93,12 +93,6 @@ void InitializeRestext() stringsText[RT_SETUP_KEY1] = TR("1) First click on the key you want to redefine."); stringsText[RT_SETUP_KEY2] = TR("2) Then press the key you want to use instead."); - stringsText[RT_MOD_LIST] = TR("Mods:"); - stringsText[RT_MOD_DETAILS] = TR("Information:"); - stringsText[RT_MOD_SUMMARY] = TR("Description:"); - stringsText[RT_MOD_ENABLE] = TR("Enable\\Enable the selected mod"); - stringsText[RT_MOD_DISABLE] = TR("Disable\\Disable the selected mod"); - stringsText[RT_PERSO_FACE] = TR("Face type:"); stringsText[RT_PERSO_GLASSES] = TR("Eyeglasses:"); stringsText[RT_PERSO_HAIR] = TR("Hair color:"); @@ -165,7 +159,16 @@ void InitializeRestext() stringsText[RT_SCOREBOARD_RESULTS_TIME]= TR("Time: %s"); stringsText[RT_SCOREBOARD_RESULTS_LINE]= TR("%s: %d pts"); - + stringsText[RT_MOD_LIST] = TR("Mods:"); + stringsText[RT_MOD_DETAILS] = TR("Information:"); + stringsText[RT_MOD_SUMMARY] = TR("Description:"); + stringsText[RT_MOD_ENABLE] = TR("Enable\\Enable the selected mod"); + stringsText[RT_MOD_DISABLE] = TR("Disable\\Disable the selected mod"); + stringsText[RT_MOD_UNKNOWN_AUTHOR] = TR("Unknown author"); + stringsText[RT_MOD_AUTHOR_FIELD_NAME] = TR("by"); + stringsText[RT_MOD_VERSION_FIELD_NAME] = TR("Version"); + stringsText[RT_MOD_WEBSITE_FIELD_NAME] = TR("Website"); + stringsText[RT_MOD_NO_SUMMARY] = TR("No description."); stringsEvent[EVENT_LABEL_CODE_BATTLE] = TR("Code battle"); diff --git a/src/common/restext.h b/src/common/restext.h index 241b6c38..5031d069 100644 --- a/src/common/restext.h +++ b/src/common/restext.h @@ -153,11 +153,16 @@ enum ResTextType RT_SCOREBOARD_RESULTS_TIME= 232, RT_SCOREBOARD_RESULTS_LINE= 233, - RT_MOD_LIST = 234, - RT_MOD_DETAILS = 235, - RT_MOD_SUMMARY = 236, - RT_MOD_ENABLE = 237, - RT_MOD_DISABLE = 238, + RT_MOD_LIST = 234, + RT_MOD_DETAILS = 235, + RT_MOD_SUMMARY = 236, + RT_MOD_ENABLE = 237, + RT_MOD_DISABLE = 238, + RT_MOD_UNKNOWN_AUTHOR = 239, + RT_MOD_AUTHOR_FIELD_NAME = 240, + RT_MOD_VERSION_FIELD_NAME = 241, + RT_MOD_WEBSITE_FIELD_NAME = 242, + RT_MOD_NO_SUMMARY = 243, RT_MAX //! < number of values }; diff --git a/src/ui/screen/screen_mod_list.cpp b/src/ui/screen/screen_mod_list.cpp index b8558f81..a216218b 100644 --- a/src/ui/screen/screen_mod_list.cpp +++ b/src/ui/screen/screen_mod_list.cpp @@ -32,6 +32,8 @@ #include "common/system/system.h" +#include "level/robotmain.h" + #include "math/func.h" #include "ui/controls/button.h" @@ -94,7 +96,7 @@ void CScreenModList::CreateInterface() pl->SetTextAlign(Gfx::TEXT_ALIGN_LEFT); pos.y = oy+sy*6.7f; - ddim.y = dim.y*4.5f; + ddim.y = dim.y*4.6f; ddim.x = dim.x*6.5f; pli = pw->CreateList(pos, ddim, 0, EVENT_INTERFACE_MOD_LIST); pli->SetState(STATE_SHADOW); @@ -112,10 +114,13 @@ void CScreenModList::CreateInterface() pl->SetTextAlign(Gfx::TEXT_ALIGN_LEFT); pos.y = oy+sy*6.7f; - ddim.y = dim.y*4.5f; + ddim.y = dim.y*4.3f; ddim.x = dim.x*6.5f; - pli = pw->CreateList(pos, ddim, 0, EVENT_INTERFACE_LIST); - pli->SetState(STATE_SHADOW); + pe = pw->CreateEdit(pos, ddim, 0, EVENT_INTERFACE_MOD_DETAILS); + pe->SetState(STATE_SHADOW); + pe->SetMaxChar(500); + pe->SetEditCap(false); // just to see + pe->SetHighlightCap(true); UpdateModDetails(); @@ -139,7 +144,7 @@ void CScreenModList::CreateInterface() pe->SetState(STATE_SHADOW); pe->SetMaxChar(500); pe->SetEditCap(false); // just to see - pe->SetHighlightCap(false); + pe->SetHighlightCap(true); UpdateModSummary(); @@ -337,14 +342,10 @@ void CScreenModList::ApplyChanges() m_modManager->SaveMods(); } - m_modManager->FindMods(); - m_modManager->SaveMods(); + m_modManager->ReloadMods(); m_empty = (m_modManager->CountMods() == 0); - m_modManager->UpdatePaths(); - m_modManager->ReloadResources(); - m_modSelectedIndex = Math::Clamp(m_modSelectedIndex, static_cast(0), m_modManager->CountMods() - 1); } @@ -372,7 +373,8 @@ void CScreenModList::UpdateModList() for (size_t i = 0; i < mods.size(); ++i) { const auto& mod = mods[i]; - pl->SetItemName(i, mod.name); + auto name = GetLanguageStringProperty(mod.data.displayName, mod.name); + pl->SetItemName(i, name); pl->SetCheck(i, mod.enabled); pl->SetEnable(i, true); } @@ -383,12 +385,80 @@ void CScreenModList::UpdateModList() void CScreenModList::UpdateModDetails() { - //TODO + CWindow* pw = static_cast(m_interface->SearchControl(EVENT_WINDOW5)); + if (pw == nullptr) return; + + CEdit* pe = static_cast(pw->SearchControl(EVENT_INTERFACE_MOD_DETAILS)); + if (pe == nullptr) return; + + if (m_empty) + { + pe->SetText("No information"); + return; + } + + std::string details{}; + + const auto& mod = m_modManager->GetMod(m_modSelectedIndex); + const auto data = mod.data; + + auto name = GetLanguageStringProperty(data.displayName, mod.name); + details += "\\b;" + name + '\n'; + + std::string authorFieldName; + GetResource(RES_TEXT, RT_MOD_AUTHOR_FIELD_NAME, authorFieldName); + details += "\\s;" + authorFieldName + " "; + if (!data.author.empty()) + { + details += data.author; + } + else + { + std::string unknownAuthor; + GetResource(RES_TEXT, RT_MOD_UNKNOWN_AUTHOR, unknownAuthor); + details += unknownAuthor; + } + details += '\n'; + + details += '\n'; + + if (!data.version.empty()) + { + std::string versionFieldName; + GetResource(RES_TEXT, RT_MOD_VERSION_FIELD_NAME, versionFieldName); + details += "\\t;" + versionFieldName + '\n' + data.version + '\n'; + } + + if (!data.website.empty()) + { + std::string websiteFieldName; + GetResource(RES_TEXT, RT_MOD_WEBSITE_FIELD_NAME, websiteFieldName); + details += "\\t;" + websiteFieldName + '\n' + data.website + '\n'; + } + + pe->SetText(details); } void CScreenModList::UpdateModSummary() { - //TODO + CWindow* pw = static_cast(m_interface->SearchControl(EVENT_WINDOW5)); + if (pw == nullptr) return; + + CEdit* pe = static_cast(pw->SearchControl(EVENT_INTERFACE_MOD_SUMMARY)); + if (pe == nullptr) return; + + std::string noSummary; + GetResource(RES_TEXT, RT_MOD_NO_SUMMARY, noSummary); + + if (m_empty) + { + pe->SetText(noSummary); + return; + } + + const auto& mod = m_modManager->GetMod(m_modSelectedIndex); + + pe->SetText(GetLanguageStringProperty(mod.data.summary, noSummary)); } void CScreenModList::UpdateEnableDisableButton() @@ -487,4 +557,23 @@ void CScreenModList::UpdateUpDownButtons() } } +std::string CScreenModList::GetLanguageStringProperty(std::unordered_map property, const std::string& fallback) +{ + std::string ret{}; + const auto language = m_app->GetLanguage(); + if (property.count(language) > 0) + { + ret = property.at(language); + } + else if (property.count(LANGUAGE_ENGLISH) > 0) + { + ret = property.at(LANGUAGE_ENGLISH); + } + else + { + ret = fallback; + } + return ret; +} + } // namespace Ui diff --git a/src/ui/screen/screen_mod_list.h b/src/ui/screen/screen_mod_list.h index e75d4baa..655406ec 100644 --- a/src/ui/screen/screen_mod_list.h +++ b/src/ui/screen/screen_mod_list.h @@ -21,11 +21,12 @@ #include "app/modman.h" +#include "ui/maindialog.h" + #include "ui/screen/screen.h" namespace Ui { -class CMainDialog; /** * \class CScreenModList @@ -78,6 +79,8 @@ protected: void UpdateApplyButton(); void UpdateUpDownButtons(); + std::string GetLanguageStringProperty(std::unordered_map property, const std::string& fallback); + protected: Ui::CMainDialog* m_dialog; From 2b96eda86d40724886c66b81b38a920ff83b5372 Mon Sep 17 00:00:00 2001 From: MrSimbax Date: Wed, 22 Jul 2020 17:13:52 +0200 Subject: [PATCH 41/98] Fix minor issues --- src/app/moddata.cpp | 12 ++++++------ src/app/moddata.h | 2 +- src/app/modman.h | 2 +- src/ui/screen/screen_mod_list.cpp | 4 +++- src/ui/screen/screen_mod_list.h | 2 +- 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/app/moddata.cpp b/src/app/moddata.cpp index 3ff716d7..c2653023 100644 --- a/src/app/moddata.cpp +++ b/src/app/moddata.cpp @@ -31,16 +31,16 @@ namespace pt = boost::property_tree; -boost::optional LoadManifest(const std::string& path, bool loaded = false); +boost::optional LoadManifest(const std::string& path); std::string GetStringProperty(const pt::ptree& manifest, const std::string& key); std::unordered_map GetLanguageStringProperty(const pt::ptree& manifest, const std::string& key); -ModData LoadModData(const std::string& path, bool loaded) +ModData LoadModData(const std::string& path) { ModData modData{}; auto manifestOptional = LoadManifest(path); - if (!manifestOptional.has_value()) + if (!manifestOptional) { return modData; } @@ -55,7 +55,7 @@ ModData LoadModData(const std::string& path, bool loaded) return modData; } -boost::optional LoadManifest(const std::string& path, bool loaded) +boost::optional LoadManifest(const std::string& path) { try { @@ -82,7 +82,7 @@ boost::optional LoadManifest(const std::string& path, bool loaded) std::string GetStringProperty(const pt::ptree& manifest, const std::string& key) { auto prop = manifest.get_optional(key); - if (prop.has_value()) + if (prop) { return prop.get(); } @@ -93,7 +93,7 @@ std::unordered_map GetLanguageStringProperty(const pt::pt { std::unordered_map ret; auto prop = manifest.get_child_optional(key); - if (prop.has_value()) + if (prop) { for (const auto& child : prop.get()) { diff --git a/src/app/moddata.h b/src/app/moddata.h index 90f3887c..551b701a 100644 --- a/src/app/moddata.h +++ b/src/app/moddata.h @@ -33,4 +33,4 @@ struct ModData }; //! Loads the metadata for a mod in the given path. -ModData LoadModData(const std::string& path, bool loaded = false); +ModData LoadModData(const std::string& path); diff --git a/src/app/modman.h b/src/app/modman.h index a937ec20..bd66117e 100644 --- a/src/app/modman.h +++ b/src/app/modman.h @@ -22,7 +22,7 @@ #include "app/moddata.h" #include -#include +#include class CApplication; class CPathManager; diff --git a/src/ui/screen/screen_mod_list.cpp b/src/ui/screen/screen_mod_list.cpp index a216218b..8868e0a9 100644 --- a/src/ui/screen/screen_mod_list.cpp +++ b/src/ui/screen/screen_mod_list.cpp @@ -43,6 +43,8 @@ #include "ui/controls/list.h" #include "ui/controls/window.h" +#include + namespace Ui { @@ -557,7 +559,7 @@ void CScreenModList::UpdateUpDownButtons() } } -std::string CScreenModList::GetLanguageStringProperty(std::unordered_map property, const std::string& fallback) +std::string CScreenModList::GetLanguageStringProperty(const std::unordered_map& property, const std::string& fallback) { std::string ret{}; const auto language = m_app->GetLanguage(); diff --git a/src/ui/screen/screen_mod_list.h b/src/ui/screen/screen_mod_list.h index 655406ec..7be1a133 100644 --- a/src/ui/screen/screen_mod_list.h +++ b/src/ui/screen/screen_mod_list.h @@ -79,7 +79,7 @@ protected: void UpdateApplyButton(); void UpdateUpDownButtons(); - std::string GetLanguageStringProperty(std::unordered_map property, const std::string& fallback); + std::string GetLanguageStringProperty(const std::unordered_map& property, const std::string& fallback); protected: Ui::CMainDialog* m_dialog; From 1be69a0a513d1abfba0ac955b3174cb2ff10ae8c Mon Sep 17 00:00:00 2001 From: MrSimbax Date: Wed, 22 Jul 2020 17:24:07 +0200 Subject: [PATCH 42/98] Fix compile errors --- src/app/moddata.cpp | 6 +++--- src/app/moddata.h | 6 +++--- src/ui/screen/screen_mod_list.cpp | 2 +- src/ui/screen/screen_mod_list.h | 4 +++- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/app/moddata.cpp b/src/app/moddata.cpp index c2653023..4ccf2f8f 100644 --- a/src/app/moddata.cpp +++ b/src/app/moddata.cpp @@ -33,7 +33,7 @@ namespace pt = boost::property_tree; boost::optional LoadManifest(const std::string& path); std::string GetStringProperty(const pt::ptree& manifest, const std::string& key); -std::unordered_map GetLanguageStringProperty(const pt::ptree& manifest, const std::string& key); +std::map GetLanguageStringProperty(const pt::ptree& manifest, const std::string& key); ModData LoadModData(const std::string& path) { @@ -89,9 +89,9 @@ std::string GetStringProperty(const pt::ptree& manifest, const std::string& key) return {}; } -std::unordered_map GetLanguageStringProperty(const pt::ptree& manifest, const std::string& key) +std::map GetLanguageStringProperty(const pt::ptree& manifest, const std::string& key) { - std::unordered_map ret; + std::map ret; auto prop = manifest.get_child_optional(key); if (prop) { diff --git a/src/app/moddata.h b/src/app/moddata.h index 551b701a..3969c812 100644 --- a/src/app/moddata.h +++ b/src/app/moddata.h @@ -21,15 +21,15 @@ #include "common/language.h" -#include +#include struct ModData { - std::unordered_map displayName{}; + std::map displayName{}; std::string author{}; std::string version{}; std::string website{}; - std::unordered_map summary{}; + std::map summary{}; }; //! Loads the metadata for a mod in the given path. diff --git a/src/ui/screen/screen_mod_list.cpp b/src/ui/screen/screen_mod_list.cpp index 8868e0a9..852e08f7 100644 --- a/src/ui/screen/screen_mod_list.cpp +++ b/src/ui/screen/screen_mod_list.cpp @@ -559,7 +559,7 @@ void CScreenModList::UpdateUpDownButtons() } } -std::string CScreenModList::GetLanguageStringProperty(const std::unordered_map& property, const std::string& fallback) +std::string CScreenModList::GetLanguageStringProperty(const std::map& property, const std::string& fallback) { std::string ret{}; const auto language = m_app->GetLanguage(); diff --git a/src/ui/screen/screen_mod_list.h b/src/ui/screen/screen_mod_list.h index 7be1a133..0da3a7c3 100644 --- a/src/ui/screen/screen_mod_list.h +++ b/src/ui/screen/screen_mod_list.h @@ -25,6 +25,8 @@ #include "ui/screen/screen.h" +#include + namespace Ui { @@ -79,7 +81,7 @@ protected: void UpdateApplyButton(); void UpdateUpDownButtons(); - std::string GetLanguageStringProperty(const std::unordered_map& property, const std::string& fallback); + std::string GetLanguageStringProperty(const std::map& property, const std::string& fallback); protected: Ui::CMainDialog* m_dialog; From df415880d08f0ece01dc9e475293a9b6ad69155b Mon Sep 17 00:00:00 2001 From: MrSimbax Date: Wed, 22 Jul 2020 17:26:46 +0200 Subject: [PATCH 43/98] Fix linter issues --- src/app/moddata.cpp | 2 +- src/app/moddata.h | 34 +++++++++++++++---------------- src/ui/screen/screen_mod_list.cpp | 2 +- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/app/moddata.cpp b/src/app/moddata.cpp index 4ccf2f8f..43ed4368 100644 --- a/src/app/moddata.cpp +++ b/src/app/moddata.cpp @@ -22,8 +22,8 @@ #include "common/logger.h" #include "common/make_unique.h" -#include "common/resources/resourcemanager.h" #include "common/resources/inputstream.h" +#include "common/resources/resourcemanager.h" #include #include diff --git a/src/app/moddata.h b/src/app/moddata.h index 3969c812..25484e8e 100644 --- a/src/app/moddata.h +++ b/src/app/moddata.h @@ -1,21 +1,21 @@ /* -* This file is part of the Colobot: Gold Edition source code -* Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam -* http://epsitec.ch; http://colobot.info; http://github.com/colobot -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -* See the GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see http://gnu.org/licenses -*/ + * This file is part of the Colobot: Gold Edition source code + * Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam + * http://epsitec.ch; http://colobot.info; http://github.com/colobot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ #pragma once diff --git a/src/ui/screen/screen_mod_list.cpp b/src/ui/screen/screen_mod_list.cpp index 852e08f7..c20fdcdc 100644 --- a/src/ui/screen/screen_mod_list.cpp +++ b/src/ui/screen/screen_mod_list.cpp @@ -421,7 +421,7 @@ void CScreenModList::UpdateModDetails() details += unknownAuthor; } details += '\n'; - + details += '\n'; if (!data.version.empty()) From 62b770f7d3ba265863bd8d3458cf795f3d24edae Mon Sep 17 00:00:00 2001 From: MrSimbax Date: Wed, 22 Jul 2020 17:50:19 +0200 Subject: [PATCH 44/98] Improve UI of mod manager a little The arrow buttons are smaller and the up button is now above the down button. What is more, the width of the back button is now the same as in other places. --- src/ui/screen/screen_mod_list.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/ui/screen/screen_mod_list.cpp b/src/ui/screen/screen_mod_list.cpp index c20fdcdc..95d42c57 100644 --- a/src/ui/screen/screen_mod_list.cpp +++ b/src/ui/screen/screen_mod_list.cpp @@ -169,13 +169,15 @@ void CScreenModList::CreateInterface() UpdateEnableDisableButton(); // Display the move up button - pos.x -= dim.x*1.3f; - ddim.x = dim.x*1; + pos.x -= dim.x*0.8f; + pos.y = oy+sy*2.48; + ddim.x = dim.x*0.5; + ddim.y = dim.y*0.5; pb = pw->CreateButton(pos, ddim, 49, EVENT_INTERFACE_MOD_MOVE_UP); pb->SetState(STATE_SHADOW); // Display the move down button - pos.x -= dim.x*1.3f; + pos.y = oy+sy*2; pb = pw->CreateButton(pos, ddim, 50, EVENT_INTERFACE_MOD_MOVE_DOWN); pb->SetState(STATE_SHADOW); @@ -183,6 +185,9 @@ void CScreenModList::CreateInterface() // Display the refresh button pos.x -= dim.x*1.3f; + pos.y = oy+sy*2; + ddim.x = dim.x*1; + ddim.y = dim.y*1; pb = pw->CreateButton(pos, ddim, 87, EVENT_INTERFACE_MODS_REFRESH); pb->SetState(STATE_SHADOW); @@ -198,7 +203,7 @@ void CScreenModList::CreateInterface() // Back button pos.x = ox+sx*3; - ddim.x = dim.x*2.3f; + ddim.x = dim.x*4; pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_BACK); pb->SetState(STATE_SHADOW); From 16795e0d49ba8b65f6bc7d6e74dc33c27561f365 Mon Sep 17 00:00:00 2001 From: MrSimbax Date: Wed, 22 Jul 2020 21:40:13 +0200 Subject: [PATCH 45/98] Use level parser instead of JSON for manifest --- src/CMakeLists.txt | 2 - src/app/moddata.cpp | 114 ------------------------------ src/app/moddata.h | 36 ---------- src/app/modman.cpp | 75 +++++++++++++++++++- src/app/modman.h | 14 +++- src/level/parser/parser.cpp | 24 +++++-- src/ui/screen/screen_mod_list.cpp | 33 +++------ src/ui/screen/screen_mod_list.h | 2 - 8 files changed, 116 insertions(+), 184 deletions(-) delete mode 100644 src/app/moddata.cpp delete mode 100644 src/app/moddata.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f00e77a6..df752615 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -145,8 +145,6 @@ set(BASE_SOURCES app/controller.h app/input.cpp app/input.h - app/moddata.cpp - app/moddata.h app/modman.cpp app/modman.h app/pathman.cpp diff --git a/src/app/moddata.cpp b/src/app/moddata.cpp deleted file mode 100644 index 43ed4368..00000000 --- a/src/app/moddata.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/* - * This file is part of the Colobot: Gold Edition source code - * Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam - * http://epsitec.ch; http://colobot.info; http://github.com/colobot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see http://gnu.org/licenses - */ - -#include "app/moddata.h" - -#include "common/logger.h" -#include "common/make_unique.h" - -#include "common/resources/inputstream.h" -#include "common/resources/resourcemanager.h" - -#include -#include -#include - -namespace pt = boost::property_tree; - -boost::optional LoadManifest(const std::string& path); -std::string GetStringProperty(const pt::ptree& manifest, const std::string& key); -std::map GetLanguageStringProperty(const pt::ptree& manifest, const std::string& key); - -ModData LoadModData(const std::string& path) -{ - ModData modData{}; - - auto manifestOptional = LoadManifest(path); - if (!manifestOptional) - { - return modData; - } - auto manifest = manifestOptional.get(); - - modData.displayName = GetLanguageStringProperty(manifest, "DisplayName"); - modData.version = GetStringProperty(manifest, "Version"); - modData.author = GetStringProperty(manifest, "Author"); - modData.website = GetStringProperty(manifest, "Website"); - modData.summary = GetLanguageStringProperty(manifest, "Summary"); - - return modData; -} - -boost::optional LoadManifest(const std::string& path) -{ - try - { - auto inputStream = MakeUnique("manifest.json"); - if (!inputStream->is_open()) - { - GetLogger()->Error("Error on parsing the manifest file %s: failed to open file\n"); - return {}; - } - - pt::ptree manifest{}; - boost::property_tree::json_parser::read_json(*inputStream, manifest); - - return manifest; - } - catch (std::exception& e) - { - GetLogger()->Warn("Error on parsing the manifest file %s: %s\n", path.c_str(), e.what()); - return {}; - } - return {}; -} - -std::string GetStringProperty(const pt::ptree& manifest, const std::string& key) -{ - auto prop = manifest.get_optional(key); - if (prop) - { - return prop.get(); - } - return {}; -} - -std::map GetLanguageStringProperty(const pt::ptree& manifest, const std::string& key) -{ - std::map ret; - auto prop = manifest.get_child_optional(key); - if (prop) - { - for (const auto& child : prop.get()) - { - Language language = LANGUAGE_ENGLISH; - std::string strLanguage = child.first.data(); - if (!ParseLanguage(strLanguage, language)) - { - GetLogger()->Warn("Error on parsing the manifest file: %s language %s is not a valid language\n", key.c_str(), strLanguage.c_str()); - continue; - } - else - { - ret.insert(std::make_pair(language, child.second.data())); - } - } - } - return ret; -} diff --git a/src/app/moddata.h b/src/app/moddata.h deleted file mode 100644 index 25484e8e..00000000 --- a/src/app/moddata.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * This file is part of the Colobot: Gold Edition source code - * Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam - * http://epsitec.ch; http://colobot.info; http://github.com/colobot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see http://gnu.org/licenses - */ - -#pragma once - -#include "common/language.h" - -#include - -struct ModData -{ - std::map displayName{}; - std::string author{}; - std::string version{}; - std::string website{}; - std::map summary{}; -}; - -//! Loads the metadata for a mod in the given path. -ModData LoadModData(const std::string& path); diff --git a/src/app/modman.cpp b/src/app/modman.cpp index a8dcf7d3..d129271f 100644 --- a/src/app/modman.cpp +++ b/src/app/modman.cpp @@ -29,6 +29,8 @@ #include "common/resources/resourcemanager.h" +#include "level/parser/parser.h" + #include #include #include @@ -107,7 +109,7 @@ void CModManager::Init() for (auto& mod : m_mods) { m_pathManager->AddMod(mod.path); - mod.data = LoadModData(mod.path); + LoadModData(mod); m_pathManager->RemoveMod(mod.path); } @@ -207,3 +209,74 @@ const std::vector& CModManager::GetMods() const { return m_mods; } + +void CModManager::LoadModData(Mod& mod) +{ + auto& data = mod.data; + + data.displayName = mod.name; + + try + { + CLevelParser levelParser("manifest.txt"); + if (levelParser.Exists()) + { + levelParser.Load(); + + CLevelParserLine* line = nullptr; + + // DisplayName + line = levelParser.GetIfDefined("DisplayName"); + if (line != nullptr && line->GetParam("text")->IsDefined()) + { + data.displayName = line->GetParam("text")->AsString(); + } + + // Author + line = levelParser.GetIfDefined("Author"); + if (line != nullptr && line->GetParam("text")->IsDefined()) + { + data.author = line->GetParam("text")->AsString(); + } + + // Version + line = levelParser.GetIfDefined("Version"); + if (line != nullptr) + { + if (line->GetParam("text")->IsDefined()) + { + data.version = line->GetParam("text")->AsString(); + } + else if (line->GetParam("major")->IsDefined() && line->GetParam("minor")->IsDefined() && line->GetParam("patch")->IsDefined()) + { + auto major = boost::lexical_cast(line->GetParam("major")->AsInt()); + auto minor = boost::lexical_cast(line->GetParam("minor")->AsInt()); + auto patch = boost::lexical_cast(line->GetParam("patch")->AsInt()); + data.version = boost::algorithm::join(std::vector{ major, minor, patch }, ","); + } + } + + // Website + line = levelParser.GetIfDefined("Website"); + if (line != nullptr && line->GetParam("text")->IsDefined()) + { + data.website = line->GetParam("text")->AsString(); + } + + // Summary + line = levelParser.GetIfDefined("Summary"); + if (line != nullptr && line->GetParam("text")->IsDefined()) + { + data.summary = line->GetParam("text")->AsString(); + } + } + else + { + GetLogger()->Warn("No manifest file for mod %s\n", mod.name.c_str()); + } + } + catch (CLevelParserException& e) + { + GetLogger()->Warn("Failed parsing manifest for mod %s: %s\n", mod.name.c_str(), e.what()); + } +} diff --git a/src/app/modman.h b/src/app/modman.h index bd66117e..57c54524 100644 --- a/src/app/modman.h +++ b/src/app/modman.h @@ -19,14 +19,21 @@ #pragma once -#include "app/moddata.h" - #include #include class CApplication; class CPathManager; +struct ModData +{ + std::string displayName{}; + std::string author{}; + std::string version{}; + std::string website{}; + std::string summary{}; +}; + struct Mod { std::string name{}; @@ -90,6 +97,9 @@ private: //! Reloads application resources so the enabled mods are applied void ReloadResources(); + //! Load mod data into mod + void LoadModData(Mod& mod); + private: CApplication* m_app; CPathManager* m_pathManager; diff --git a/src/level/parser/parser.cpp b/src/level/parser/parser.cpp index e8f871bd..1bf78a24 100644 --- a/src/level/parser/parser.cpp +++ b/src/level/parser/parser.cpp @@ -41,6 +41,7 @@ #include #include #include +#include CLevelParser::CLevelParser() { @@ -172,13 +173,28 @@ void CLevelParser::Load() boost::replace_all(line, "\t", " "); // replace tab by space // ignore comments - std::size_t comment = line.find("//"); - if (comment != std::string::npos) - line = line.substr(0, comment); + size_t pos = 0; + std::string linesuffix = line; + boost::regex commentRegex{ R"(("[^"]*")|('[^']*')|(//.*$))" }; + boost::smatch matches; + while (boost::regex_search(linesuffix, matches, commentRegex)) + { + if (matches[3].matched) + { + pos += std::distance(linesuffix.cbegin(), matches.prefix().second); + line = line.substr(0, pos); + linesuffix = ""; + } + else + { + pos += std::distance(linesuffix.cbegin(), matches.suffix().first); + linesuffix = matches.suffix().str(); + } + } boost::algorithm::trim(line); - std::size_t pos = line.find_first_of(" \t\n"); + pos = line.find_first_of(" \t\n"); std::string command = line.substr(0, pos); if (pos != std::string::npos) { diff --git a/src/ui/screen/screen_mod_list.cpp b/src/ui/screen/screen_mod_list.cpp index 95d42c57..8717ed57 100644 --- a/src/ui/screen/screen_mod_list.cpp +++ b/src/ui/screen/screen_mod_list.cpp @@ -380,7 +380,7 @@ void CScreenModList::UpdateModList() for (size_t i = 0; i < mods.size(); ++i) { const auto& mod = mods[i]; - auto name = GetLanguageStringProperty(mod.data.displayName, mod.name); + auto name = mod.data.displayName; pl->SetItemName(i, name); pl->SetCheck(i, mod.enabled); pl->SetEnable(i, true); @@ -409,8 +409,7 @@ void CScreenModList::UpdateModDetails() const auto& mod = m_modManager->GetMod(m_modSelectedIndex); const auto data = mod.data; - auto name = GetLanguageStringProperty(data.displayName, mod.name); - details += "\\b;" + name + '\n'; + details += "\\b;" + data.displayName + '\n'; std::string authorFieldName; GetResource(RES_TEXT, RT_MOD_AUTHOR_FIELD_NAME, authorFieldName); @@ -465,7 +464,14 @@ void CScreenModList::UpdateModSummary() const auto& mod = m_modManager->GetMod(m_modSelectedIndex); - pe->SetText(GetLanguageStringProperty(mod.data.summary, noSummary)); + if (!mod.data.summary.empty()) + { + pe->SetText(mod.data.summary); + } + else + { + pe->SetText(noSummary); + } } void CScreenModList::UpdateEnableDisableButton() @@ -564,23 +570,4 @@ void CScreenModList::UpdateUpDownButtons() } } -std::string CScreenModList::GetLanguageStringProperty(const std::map& property, const std::string& fallback) -{ - std::string ret{}; - const auto language = m_app->GetLanguage(); - if (property.count(language) > 0) - { - ret = property.at(language); - } - else if (property.count(LANGUAGE_ENGLISH) > 0) - { - ret = property.at(LANGUAGE_ENGLISH); - } - else - { - ret = fallback; - } - return ret; -} - } // namespace Ui diff --git a/src/ui/screen/screen_mod_list.h b/src/ui/screen/screen_mod_list.h index 0da3a7c3..639fd775 100644 --- a/src/ui/screen/screen_mod_list.h +++ b/src/ui/screen/screen_mod_list.h @@ -81,8 +81,6 @@ protected: void UpdateApplyButton(); void UpdateUpDownButtons(); - std::string GetLanguageStringProperty(const std::map& property, const std::string& fallback); - protected: Ui::CMainDialog* m_dialog; From 51668c12d7c9b055549ca381356b4642d3514524 Mon Sep 17 00:00:00 2001 From: MrSimbax Date: Thu, 23 Jul 2020 17:44:38 +0200 Subject: [PATCH 46/98] Add changes listing to mods It's just listing directories of a mod for now, but should give some idea what the mod changes. Also moved some functionality from pathman to modman. Mods added with the `-mod` parameter are now managed by modman. --- po/colobot.pot | 6 ++ po/cs.po | 7 ++ po/de.po | 7 ++ po/fr.po | 7 ++ po/pl.po | 6 ++ po/pt.po | 7 ++ po/ru.po | 7 ++ src/app/modman.cpp | 39 +++++++++-- src/app/modman.h | 6 ++ src/app/pathman.cpp | 88 ++++++++++-------------- src/app/pathman.h | 16 ++--- src/common/resources/resourcemanager.cpp | 4 +- src/common/resources/resourcemanager.h | 2 +- src/common/restext.cpp | 2 + src/common/restext.h | 4 +- src/ui/screen/screen_mod_list.cpp | 19 +++++ 16 files changed, 158 insertions(+), 69 deletions(-) diff --git a/po/colobot.pot b/po/colobot.pot index b459a8f3..49ecac68 100644 --- a/po/colobot.pot +++ b/po/colobot.pot @@ -327,9 +327,15 @@ msgstr "" msgid "Website" msgstr "" +msgid "Changes" +msgstr "" + msgid "No description." msgstr "" +msgid "No changes." +msgstr "" + msgid "Code battle" msgstr "" diff --git a/po/cs.po b/po/cs.po index 6fb3aa3e..829446fd 100644 --- a/po/cs.po +++ b/po/cs.po @@ -374,6 +374,10 @@ msgstr "Změnit kameru\\Přepíná mezi kamerou na robotu a za robotem" msgid "Change player\\Change player" msgstr "Změnit hráče\\Změnit hráče" +#, fuzzy +msgid "Changes" +msgstr "Hlavolamy" + msgid "Chapters:" msgstr "Kapitoly:" @@ -988,6 +992,9 @@ msgstr "Další objekt\\Vybere následující objekt" msgid "No" msgstr "Ne" +msgid "No changes." +msgstr "" + #, fuzzy msgid "No description." msgstr "Rozlišení:" diff --git a/po/de.po b/po/de.po index 23b581f4..06c7cb73 100644 --- a/po/de.po +++ b/po/de.po @@ -375,6 +375,10 @@ msgstr "Andere Kamera\\Sichtpunkt einstellen" msgid "Change player\\Change player" msgstr "Anderer Spieler\\Spielername ändern" +#, fuzzy +msgid "Changes" +msgstr "Herausforderungen" + msgid "Chapters:" msgstr "Liste der Kapitel:" @@ -1004,6 +1008,9 @@ msgstr "Nächstes auswählen\\Nächstes Objekt auswählen" msgid "No" msgstr "Nein" +msgid "No changes." +msgstr "" + #, fuzzy msgid "No description." msgstr "Auflösung:" diff --git a/po/fr.po b/po/fr.po index 6c13748d..1d096618 100644 --- a/po/fr.po +++ b/po/fr.po @@ -377,6 +377,10 @@ msgstr "Changement de caméra\\Autre de point de vue" msgid "Change player\\Change player" msgstr "Autre joueur\\Choix du nom du joueur" +#, fuzzy +msgid "Changes" +msgstr "Défis" + msgid "Chapters:" msgstr "Liste des chapitres :" @@ -1006,6 +1010,9 @@ msgstr "Sélectionner l'objet suivant\\Sélectionner l'objet suivant" msgid "No" msgstr "Non" +msgid "No changes." +msgstr "" + #, fuzzy msgid "No description." msgstr "Résolutions :" diff --git a/po/pl.po b/po/pl.po index 9f00c679..cc2bcd96 100644 --- a/po/pl.po +++ b/po/pl.po @@ -373,6 +373,9 @@ msgstr "Zmień kamerę\\Przełącza pomiędzy kamerą pokładową i śledzącą" msgid "Change player\\Change player" msgstr "Zmień gracza\\Zmień gracza" +msgid "Changes" +msgstr "Zmiany" + msgid "Chapters:" msgstr "Rozdziały:" @@ -984,6 +987,9 @@ msgstr "Następny obiekt\\Zaznacza następny obiekt" msgid "No" msgstr "Nie" +msgid "No changes." +msgstr "Brak zmian." + msgid "No description." msgstr "Brak opisu." diff --git a/po/pt.po b/po/pt.po index 05285903..b8088c59 100644 --- a/po/pt.po +++ b/po/pt.po @@ -371,6 +371,10 @@ msgstr "Mudar câmera\\Alterna entre câmera incorporada e câmera seguidora" msgid "Change player\\Change player" msgstr "Mudar jogador\\Mudar jogador" +#, fuzzy +msgid "Changes" +msgstr "Desafios" + msgid "Chapters:" msgstr "Capítulos:" @@ -1001,6 +1005,9 @@ msgstr "Próximo objeto\\Selecionar o próximo objeto" msgid "No" msgstr "Não" +msgid "No changes." +msgstr "" + #, fuzzy msgid "No description." msgstr "Resolução:" diff --git a/po/ru.po b/po/ru.po index 2a4dccaa..bb3db29a 100644 --- a/po/ru.po +++ b/po/ru.po @@ -378,6 +378,10 @@ msgstr "Изменить вид\\Переключение между борто msgid "Change player\\Change player" msgstr "Новый игрок\\Выберите имя для игрока" +#, fuzzy +msgid "Changes" +msgstr "Задания" + msgid "Chapters:" msgstr "Разделы:" @@ -1012,6 +1016,9 @@ msgstr "Следующий объект\\Выбор следующего объ msgid "No" msgstr "Нет" +msgid "No changes." +msgstr "" + #, fuzzy msgid "No description." msgstr "Разрешение:" diff --git a/src/app/modman.cpp b/src/app/modman.cpp index d129271f..54596b63 100644 --- a/src/app/modman.cpp +++ b/src/app/modman.cpp @@ -67,7 +67,7 @@ void CModManager::Init() } // Search the folders for mods - const auto rawPaths = m_pathManager->FindMods(); + auto rawPaths = m_pathManager->FindMods(); std::map modPaths; for (const auto& path : rawPaths) { @@ -108,9 +108,9 @@ void CModManager::Init() // Load the metadata for each mod for (auto& mod : m_mods) { - m_pathManager->AddMod(mod.path); + MountMod(mod, "/temp/mod"); LoadModData(mod); - m_pathManager->RemoveMod(mod.path); + UnmountMod(mod); } UpdatePaths(); @@ -118,8 +118,8 @@ void CModManager::Init() void CModManager::ReloadMods() { + UnmountAllMods(); m_mods.clear(); - m_pathManager->RemoveAllMods(); Init(); @@ -165,12 +165,11 @@ size_t CModManager::MoveDown(size_t i) void CModManager::UpdatePaths() { - m_pathManager->RemoveAllMods(); for (const auto& mod : m_mods) { if (mod.enabled) { - m_pathManager->AddMod(mod.path); + MountMod(mod); } } } @@ -218,7 +217,7 @@ void CModManager::LoadModData(Mod& mod) try { - CLevelParser levelParser("manifest.txt"); + CLevelParser levelParser("temp/mod/manifest.txt"); if (levelParser.Exists()) { levelParser.Load(); @@ -279,4 +278,30 @@ void CModManager::LoadModData(Mod& mod) { GetLogger()->Warn("Failed parsing manifest for mod %s: %s\n", mod.name.c_str(), e.what()); } + + // Changes + data.changes = CResourceManager::ListDirectories("temp/mod"); +} + +void CModManager::MountMod(const Mod& mod, const std::string& mountPoint) +{ + GetLogger()->Debug("Mounting mod: '%s' at path %s\n", mod.path.c_str(), mountPoint.c_str()); + CResourceManager::AddLocation(mod.path, true, mountPoint); +} + +void CModManager::UnmountMod(const Mod& mod) +{ + if (CResourceManager::LocationExists(mod.path)) + { + GetLogger()->Debug("Unmounting mod: '%s'\n", mod.path.c_str()); + CResourceManager::RemoveLocation(mod.path); + } +} + +void CModManager::UnmountAllMods() +{ + for (const auto& mod : m_mods) + { + UnmountMod(mod); + } } diff --git a/src/app/modman.h b/src/app/modman.h index 57c54524..a8af565e 100644 --- a/src/app/modman.h +++ b/src/app/modman.h @@ -19,6 +19,7 @@ #pragma once +#include #include #include @@ -32,6 +33,7 @@ struct ModData std::string version{}; std::string website{}; std::string summary{}; + std::vector changes{}; }; struct Mod @@ -100,6 +102,10 @@ private: //! Load mod data into mod void LoadModData(Mod& mod); + void MountMod(const Mod& mod, const std::string& mountPoint = ""); + void UnmountMod(const Mod& mod); + void UnmountAllMods(); + private: CApplication* m_app; CPathManager* m_pathManager; diff --git a/src/app/pathman.cpp b/src/app/pathman.cpp index e353ec1a..e4c385dd 100644 --- a/src/app/pathman.cpp +++ b/src/app/pathman.cpp @@ -64,56 +64,6 @@ void CPathManager::SetSavePath(const std::string &savePath) m_savePath = savePath; } -void CPathManager::AddModSearchDir(const std::string &modSearchDirPath) -{ - m_modSearchDirs.push_back(modSearchDirPath); -} - -void CPathManager::AddMod(const std::string &modPath) -{ - GetLogger()->Debug("Adding mod: '%s'\n", modPath.c_str()); - CResourceManager::AddLocation(modPath, true); - m_mods.push_back(modPath); -} - -void CPathManager::RemoveMod(const std::string &modPath) -{ - GetLogger()->Debug("Removing mod: '%s'\n", modPath.c_str()); - CResourceManager::RemoveLocation(modPath); - auto it = std::find(m_mods.cbegin(), m_mods.cend(), modPath); - if (it != m_mods.cend()) - m_mods.erase(it); -} - -void CPathManager::RemoveAllMods() -{ - for (const auto& modPath : m_mods) - { - CResourceManager::RemoveLocation(modPath); - } - m_mods.clear(); -} - -bool CPathManager::ModLoaded(const std::string& modPath) -{ - return std::find(m_mods.cbegin(), m_mods.cend(), modPath) != m_mods.end(); -} - -std::vector CPathManager::FindMods() const -{ - std::vector mods; - GetLogger()->Info("Found mods:\n"); - for (const auto &searchPath : m_modSearchDirs) - { - for (const auto &modPath : FindModsInDir(searchPath)) - { - GetLogger()->Info(" * %s\n", modPath.c_str()); - mods.push_back(modPath); - } - } - return mods; -} - const std::string& CPathManager::GetDataPath() { return m_dataPath; @@ -191,6 +141,44 @@ void CPathManager::InitPaths() GetLogger()->Debug(" * %s\n", path.c_str()); } +void CPathManager::AddMod(const std::string &path) +{ + m_mods.push_back(path); +} + +std::vector CPathManager::FindMods() const +{ + std::vector mods; + GetLogger()->Info("Found mods:\n"); + for (const auto &searchPath : m_modSearchDirs) + { + for (const auto &modPath : FindModsInDir(searchPath)) + { + GetLogger()->Info(" * %s\n", modPath.c_str()); + mods.push_back(modPath); + } + } + GetLogger()->Info("Additional mod paths:\n"); + for (const auto& modPath : m_mods) + { + if (boost::filesystem::exists(modPath)) + { + GetLogger()->Info(" * %s\n", modPath.c_str()); + mods.push_back(modPath); + } + else + { + GetLogger()->Warn("Mod does not exist: %s\n", modPath.c_str()); + } + } + return mods; +} + +void CPathManager::AddModSearchDir(const std::string &modSearchDirPath) +{ + m_modSearchDirs.push_back(modSearchDirPath); +} + std::vector CPathManager::FindModsInDir(const std::string &dir) const { std::vector ret; diff --git a/src/app/pathman.h b/src/app/pathman.h index 2fedfee6..d1ba4bbe 100644 --- a/src/app/pathman.h +++ b/src/app/pathman.h @@ -37,12 +37,6 @@ public: void SetDataPath(const std::string &dataPath); void SetLangPath(const std::string &langPath); void SetSavePath(const std::string &savePath); - void AddModSearchDir(const std::string &modSearchDirPath); - void AddMod(const std::string &modPath); - void RemoveMod(const std::string &modPath); - void RemoveAllMods(); - bool ModLoaded(const std::string& modPath); - std::vector FindMods() const; const std::string& GetDataPath(); const std::string& GetLangPath(); @@ -53,8 +47,14 @@ public: //! Loads configured paths void InitPaths(); + //! Adds a path to a mod + void AddMod(const std::string& path); + //! Find paths to mods in mod search directories + std::vector FindMods() const; + //! Adds a mod search directory + void AddModSearchDir(const std::string &modSearchDirPath); + private: - //! Loads all mods from given directory std::vector FindModsInDir(const std::string &dir) const; private: @@ -66,6 +66,6 @@ private: std::string m_savePath; //! Mod search paths std::vector m_modSearchDirs; - //! Mod paths + //! Additional mod paths std::vector m_mods; }; diff --git a/src/common/resources/resourcemanager.cpp b/src/common/resources/resourcemanager.cpp index bddb5236..7c572483 100644 --- a/src/common/resources/resourcemanager.cpp +++ b/src/common/resources/resourcemanager.cpp @@ -62,9 +62,9 @@ std::string CResourceManager::CleanPath(const std::string& path) } -bool CResourceManager::AddLocation(const std::string &location, bool prepend) +bool CResourceManager::AddLocation(const std::string &location, bool prepend, const std::string &mountPoint) { - if (!PHYSFS_mount(location.c_str(), nullptr, prepend ? 0 : 1)) + if (!PHYSFS_mount(location.c_str(), mountPoint.c_str(), prepend ? 0 : 1)) { GetLogger()->Error("Error while mounting \"%s\": %s\n", location.c_str(), PHYSFS_getLastError()); return false; diff --git a/src/common/resources/resourcemanager.h b/src/common/resources/resourcemanager.h index 0a1bca16..d15a6f02 100644 --- a/src/common/resources/resourcemanager.h +++ b/src/common/resources/resourcemanager.h @@ -36,7 +36,7 @@ public: static std::string CleanPath(const std::string &path); //! Add a location to the search path - static bool AddLocation(const std::string &location, bool prepend = true); + static bool AddLocation(const std::string &location, bool prepend = true, const std::string &mountPoint = ""); //! Remove a location from the search path static bool RemoveLocation(const std::string &location); //! List all locations in the search path diff --git a/src/common/restext.cpp b/src/common/restext.cpp index 294aa1eb..becde931 100644 --- a/src/common/restext.cpp +++ b/src/common/restext.cpp @@ -168,7 +168,9 @@ void InitializeRestext() stringsText[RT_MOD_AUTHOR_FIELD_NAME] = TR("by"); stringsText[RT_MOD_VERSION_FIELD_NAME] = TR("Version"); stringsText[RT_MOD_WEBSITE_FIELD_NAME] = TR("Website"); + stringsText[RT_MOD_CHANGES_FIELD_NAME] = TR("Changes"); stringsText[RT_MOD_NO_SUMMARY] = TR("No description."); + stringsText[RT_MOD_NO_CHANGES] = TR("No changes."); stringsEvent[EVENT_LABEL_CODE_BATTLE] = TR("Code battle"); diff --git a/src/common/restext.h b/src/common/restext.h index 5031d069..165c52cd 100644 --- a/src/common/restext.h +++ b/src/common/restext.h @@ -162,7 +162,9 @@ enum ResTextType RT_MOD_AUTHOR_FIELD_NAME = 240, RT_MOD_VERSION_FIELD_NAME = 241, RT_MOD_WEBSITE_FIELD_NAME = 242, - RT_MOD_NO_SUMMARY = 243, + RT_MOD_CHANGES_FIELD_NAME = 243, + RT_MOD_NO_SUMMARY = 244, + RT_MOD_NO_CHANGES = 245, RT_MAX //! < number of values }; diff --git a/src/ui/screen/screen_mod_list.cpp b/src/ui/screen/screen_mod_list.cpp index 8717ed57..f151f781 100644 --- a/src/ui/screen/screen_mod_list.cpp +++ b/src/ui/screen/screen_mod_list.cpp @@ -442,7 +442,26 @@ void CScreenModList::UpdateModDetails() details += "\\t;" + websiteFieldName + '\n' + data.website + '\n'; } + std::string changesFieldName; + GetResource(RES_TEXT, RT_MOD_CHANGES_FIELD_NAME, changesFieldName); + details += "\\t;" + changesFieldName + '\n'; + if (!data.changes.empty()) + { + for (const auto& change : data.changes) + { + details += change + '\n'; + } + } + else + { + std::string noChanges; + GetResource(RES_TEXT, RT_MOD_NO_CHANGES, noChanges); + details += noChanges; + } + pe->SetText(details); + + pe->SetFirstLine(0); } void CScreenModList::UpdateModSummary() From e6ce4112c67932c007af3eff4be8805a2652c593 Mon Sep 17 00:00:00 2001 From: MrSimbax Date: Thu, 23 Jul 2020 17:57:25 +0200 Subject: [PATCH 47/98] Update translations --- po/cs.po | 22 ++++++---------------- po/de.po | 22 ++++++---------------- po/fr.po | 22 ++++++---------------- po/pl.po | 4 ---- po/pt.po | 22 ++++++---------------- po/ru.po | 22 ++++++---------------- 6 files changed, 30 insertions(+), 84 deletions(-) diff --git a/po/cs.po b/po/cs.po index 829446fd..c7755b3b 100644 --- a/po/cs.po +++ b/po/cs.po @@ -374,9 +374,8 @@ msgstr "Změnit kameru\\Přepíná mezi kamerou na robotu a za robotem" msgid "Change player\\Change player" msgstr "Změnit hráče\\Změnit hráče" -#, fuzzy msgid "Changes" -msgstr "Hlavolamy" +msgstr "" msgid "Chapters:" msgstr "Kapitoly:" @@ -486,9 +485,8 @@ msgstr "Vrtná věž" msgid "Descend\\Reduces the power of the jet" msgstr "Klesat\\Snížit tah tryskového motoru" -#, fuzzy msgid "Description:" -msgstr "Rozlišení:" +msgstr "" msgid "Destroy" msgstr "Zbourat" @@ -502,9 +500,8 @@ msgstr "Drtič" msgid "Device\\Driver and resolution settings" msgstr "Obrazovka\\Nastavení grafické karty a rozlišení" -#, fuzzy msgid "Disable\\Disable the selected mod" -msgstr "Smazat\\Smaže vybraný soubor" +msgstr "" msgid "Dividing by zero" msgstr "Dělení nulou" @@ -552,9 +549,8 @@ msgstr "Vejce" msgid "Empty character constant" msgstr "" -#, fuzzy msgid "Enable\\Enable the selected mod" -msgstr "Nahrát\\Nahraje vybranou misi" +msgstr "" msgid "End of block missing" msgstr "Chybí konec bloku" @@ -995,9 +991,8 @@ msgstr "Ne" msgid "No changes." msgstr "" -#, fuzzy msgid "No description." -msgstr "Rozlišení:" +msgstr "" msgid "No energy in the subsoil" msgstr "Pod povrchem není zdroj energie" @@ -1746,9 +1741,8 @@ msgstr "Jednotka" msgid "Unknown Object" msgstr "Neznámý objekt" -#, fuzzy msgid "Unknown author" -msgstr "Neznámá funkce" +msgstr "" msgid "Unknown command" msgstr "Neznámý příkaz" @@ -2004,7 +1998,3 @@ msgstr "colobot.info" msgid "epsitec.com" msgstr "epsitec.com" - -#, fuzzy -#~ msgid "No mods installed!" -#~ msgstr "Žádné uživatelské mapy nejsou nainstalovány!" diff --git a/po/de.po b/po/de.po index 06c7cb73..059898a0 100644 --- a/po/de.po +++ b/po/de.po @@ -375,9 +375,8 @@ msgstr "Andere Kamera\\Sichtpunkt einstellen" msgid "Change player\\Change player" msgstr "Anderer Spieler\\Spielername ändern" -#, fuzzy msgid "Changes" -msgstr "Herausforderungen" +msgstr "" msgid "Chapters:" msgstr "Liste der Kapitel:" @@ -487,9 +486,8 @@ msgstr "Bohrturm" msgid "Descend\\Reduces the power of the jet" msgstr "Sinken\\Leistung des Triebwerks drosseln" -#, fuzzy msgid "Description:" -msgstr "Auflösung:" +msgstr "" msgid "Destroy" msgstr "Zerstören" @@ -503,9 +501,8 @@ msgstr "Einstampfer" msgid "Device\\Driver and resolution settings" msgstr "Bildschirm\\Driver und Bildschirmauflösung" -#, fuzzy msgid "Disable\\Disable the selected mod" -msgstr "Löschen\\Löscht die gespeicherte Mission" +msgstr "" msgid "Dividing by zero" msgstr "Division durch Null" @@ -553,9 +550,8 @@ msgstr "Ei" msgid "Empty character constant" msgstr "" -#, fuzzy msgid "Enable\\Enable the selected mod" -msgstr "Laden\\Öffnet eine gespeicherte Mission" +msgstr "" msgid "End of block missing" msgstr "Es fehlt eine geschlossene geschweifte Klammer \"}\" (Ende des Blocks)" @@ -1011,9 +1007,8 @@ msgstr "Nein" msgid "No changes." msgstr "" -#, fuzzy msgid "No description." -msgstr "Auflösung:" +msgstr "" msgid "No energy in the subsoil" msgstr "Kein unterirdisches Energievorkommen" @@ -1763,9 +1758,8 @@ msgstr "Einheit" msgid "Unknown Object" msgstr "Das Objekt existiert nicht" -#, fuzzy msgid "Unknown author" -msgstr "Unbekannte Funktion" +msgstr "" msgid "Unknown command" msgstr "Befehl unbekannt" @@ -2099,10 +2093,6 @@ msgstr "epsitec.com" #~ msgid "Mouse shadow\\Gives the mouse a shadow" #~ msgstr "Schatten unter der Maus\\Ein Schatten erscheint unter der Maus" -#, fuzzy -#~ msgid "No mods installed!" -#~ msgstr "Keine benutzerdefinierten Level vorhanden" - #~ msgid "No other robot" #~ msgstr "Kein anderer Roboter" diff --git a/po/fr.po b/po/fr.po index 1d096618..551267e5 100644 --- a/po/fr.po +++ b/po/fr.po @@ -377,9 +377,8 @@ msgstr "Changement de caméra\\Autre de point de vue" msgid "Change player\\Change player" msgstr "Autre joueur\\Choix du nom du joueur" -#, fuzzy msgid "Changes" -msgstr "Défis" +msgstr "" msgid "Chapters:" msgstr "Liste des chapitres :" @@ -489,9 +488,8 @@ msgstr "Derrick" msgid "Descend\\Reduces the power of the jet" msgstr "Descendre\\Diminuer la puissance du réacteur" -#, fuzzy msgid "Description:" -msgstr "Résolutions :" +msgstr "" msgid "Destroy" msgstr "Détruire" @@ -505,9 +503,8 @@ msgstr "Destructeur" msgid "Device\\Driver and resolution settings" msgstr "Affichage\\Pilote et résolution d'affichage" -#, fuzzy msgid "Disable\\Disable the selected mod" -msgstr "Supprimer\\Supprime l'enregistrement sélectionné" +msgstr "" msgid "Dividing by zero" msgstr "Division par zéro" @@ -555,9 +552,8 @@ msgstr "Oeuf" msgid "Empty character constant" msgstr "" -#, fuzzy msgid "Enable\\Enable the selected mod" -msgstr "Charger\\Charger la mission sélectionnée" +msgstr "" msgid "End of block missing" msgstr "Il manque la fin du bloc" @@ -1013,9 +1009,8 @@ msgstr "Non" msgid "No changes." msgstr "" -#, fuzzy msgid "No description." -msgstr "Résolutions :" +msgstr "" msgid "No energy in the subsoil" msgstr "Pas d'énergie en sous-sol" @@ -1765,9 +1760,8 @@ msgstr "Unité" msgid "Unknown Object" msgstr "Objet inconnu" -#, fuzzy msgid "Unknown author" -msgstr "Routine inconnue" +msgstr "" msgid "Unknown command" msgstr "Commande inconnue" @@ -2103,10 +2097,6 @@ msgstr "epsitec.com" #~ msgid "Mouse shadow\\Gives the mouse a shadow" #~ msgstr "Souris ombrée\\Jolie souris avec une ombre" -#, fuzzy -#~ msgid "No mods installed!" -#~ msgstr "Pas de niveaux spéciaux installés !" - #~ msgid "No other robot" #~ msgstr "Pas d'autre robot" diff --git a/po/pl.po b/po/pl.po index cc2bcd96..0db014ed 100644 --- a/po/pl.po +++ b/po/pl.po @@ -2076,10 +2076,6 @@ msgstr "epsitec.com" #~ msgid "Mouse shadow\\Gives the mouse a shadow" #~ msgstr "Cień kursora myszy\\Dodaje cień kursorowi myszy" -#, fuzzy -#~ msgid "No mods installed!" -#~ msgstr "Brak zainstalowanych poziomów użytkownika!" - #~ msgid "No other robot" #~ msgstr "Brak innego robota" diff --git a/po/pt.po b/po/pt.po index b8088c59..e1f8dc99 100644 --- a/po/pt.po +++ b/po/pt.po @@ -371,9 +371,8 @@ msgstr "Mudar câmera\\Alterna entre câmera incorporada e câmera seguidora" msgid "Change player\\Change player" msgstr "Mudar jogador\\Mudar jogador" -#, fuzzy msgid "Changes" -msgstr "Desafios" +msgstr "" msgid "Chapters:" msgstr "Capítulos:" @@ -484,9 +483,8 @@ msgstr "Extrator" msgid "Descend\\Reduces the power of the jet" msgstr "Descer\\Diminui o poder do jato" -#, fuzzy msgid "Description:" -msgstr "Resolução:" +msgstr "" msgid "Destroy" msgstr "Destruir" @@ -500,9 +498,8 @@ msgstr "Destruidor" msgid "Device\\Driver and resolution settings" msgstr "Dispositivo\\Configurações de driver e resolução" -#, fuzzy msgid "Disable\\Disable the selected mod" -msgstr "Excluir\\Exclui o arquivo selecionado" +msgstr "" msgid "Dividing by zero" msgstr "Dividindo por zero" @@ -550,9 +547,8 @@ msgstr "Ovo" msgid "Empty character constant" msgstr "" -#, fuzzy msgid "Enable\\Enable the selected mod" -msgstr "Carregar\\Carrega a missão selecionada" +msgstr "" msgid "End of block missing" msgstr "Fim do bloco ausente" @@ -1008,9 +1004,8 @@ msgstr "Não" msgid "No changes." msgstr "" -#, fuzzy msgid "No description." -msgstr "Resolução:" +msgstr "" msgid "No energy in the subsoil" msgstr "Nenhuma energia no subsolo" @@ -1760,9 +1755,8 @@ msgstr "Unidade" msgid "Unknown Object" msgstr "Objeto desconhecido" -#, fuzzy msgid "Unknown author" -msgstr "Função desconhecida" +msgstr "" msgid "Unknown command" msgstr "Comando desconhecido" @@ -2101,10 +2095,6 @@ msgstr "epsitec.com" #~ msgid "Mouse shadow\\Gives the mouse a shadow" #~ msgstr "Souris ombrée\\Jolie souris avec une ombre" -#, fuzzy -#~ msgid "No mods installed!" -#~ msgstr "Nenhum nível de usuário instalado!" - #~ msgid "No other robot" #~ msgstr "Pas d'autre robot" diff --git a/po/ru.po b/po/ru.po index bb3db29a..974d6ab1 100644 --- a/po/ru.po +++ b/po/ru.po @@ -378,9 +378,8 @@ msgstr "Изменить вид\\Переключение между борто msgid "Change player\\Change player" msgstr "Новый игрок\\Выберите имя для игрока" -#, fuzzy msgid "Changes" -msgstr "Задания" +msgstr "" msgid "Chapters:" msgstr "Разделы:" @@ -493,9 +492,8 @@ msgstr "Космический корабль" msgid "Descend\\Reduces the power of the jet" msgstr "Снижение и посадка\\Понижение мощности реактивного двигателя" -#, fuzzy msgid "Description:" -msgstr "Разрешение:" +msgstr "" msgid "Destroy" msgstr "Уничтожить" @@ -509,9 +507,8 @@ msgstr "Уничтожитель" msgid "Device\\Driver and resolution settings" msgstr "Устройство\\Драйвер и настройки разрешения" -#, fuzzy msgid "Disable\\Disable the selected mod" -msgstr "Удалить\\Удаление выбранного файла" +msgstr "" msgid "Dividing by zero" msgstr "Деление на ноль (запрещено!)" @@ -559,9 +556,8 @@ msgstr "Яйцо" msgid "Empty character constant" msgstr "" -#, fuzzy msgid "Enable\\Enable the selected mod" -msgstr "Загрузить\\Загрузить выбранную миссию" +msgstr "" msgid "End of block missing" msgstr "Отсутствует конец блока" @@ -1019,9 +1015,8 @@ msgstr "Нет" msgid "No changes." msgstr "" -#, fuzzy msgid "No description." -msgstr "Разрешение:" +msgstr "" msgid "No energy in the subsoil" msgstr "Под землей нет запасов энергии" @@ -1776,9 +1771,8 @@ msgstr "Юнит" msgid "Unknown Object" msgstr "Неизвестный объект" -#, fuzzy msgid "Unknown author" -msgstr "Неизвестная функция" +msgstr "" msgid "Unknown command" msgstr "Неизвестная команда" @@ -2111,10 +2105,6 @@ msgstr "epsitec.com" #~ msgid "Mouse shadow\\Gives the mouse a shadow" #~ msgstr "Тень мыши\\Мышь отбрасывает тень" -#, fuzzy -#~ msgid "No mods installed!" -#~ msgstr "Не установленны пользовательские уровни!" - #~ msgid "No other robot" #~ msgstr "Нет робота" From 253cca379b94575b699e7bc9438f3ad635c98384 Mon Sep 17 00:00:00 2001 From: MrSimbax Date: Thu, 23 Jul 2020 18:07:02 +0200 Subject: [PATCH 48/98] List which level subdirectory a mod changes --- src/app/modman.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/app/modman.cpp b/src/app/modman.cpp index 54596b63..76afa079 100644 --- a/src/app/modman.cpp +++ b/src/app/modman.cpp @@ -281,6 +281,17 @@ void CModManager::LoadModData(Mod& mod) // Changes data.changes = CResourceManager::ListDirectories("temp/mod"); + auto levelsIt = std::find(data.changes.begin(), data.changes.end(), "levels"); + if (levelsIt != data.changes.end()) + { + auto levelsDirs = CResourceManager::ListDirectories("temp/mod/levels"); + if (!levelsDirs.empty()) + { + std::transform(levelsDirs.begin(), levelsDirs.end(), levelsDirs.begin(), [](const std::string& dir) { return "levels/" + dir; }); + levelsIt = data.changes.erase(levelsIt); + data.changes.insert(levelsIt, levelsDirs.begin(), levelsDirs.end()); + } + } } void CModManager::MountMod(const Mod& mod, const std::string& mountPoint) From fbe21918002fe608d1104369517e9ada4cc4f415 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Przyby=C5=82?= Date: Fri, 24 Jul 2020 02:20:06 +0200 Subject: [PATCH 49/98] Allow producing objects with no keyword in CBOT (#1335) --- src/CMakeLists.txt | 1 + src/object/object_type.cpp | 236 +++++++++++++++++++++++++++++++++++++ src/object/object_type.h | 2 + src/script/scriptfunc.cpp | 2 +- 4 files changed, 240 insertions(+), 1 deletion(-) create mode 100644 src/object/object_type.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index aefd0fad..b0dc5dd8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -418,6 +418,7 @@ set(BASE_SOURCES object/object_interface_type.h object/object_manager.cpp object/object_manager.h + object/object_type.cpp object/object_type.h object/old_object.cpp object/old_object.h diff --git a/src/object/object_type.cpp b/src/object/object_type.cpp new file mode 100644 index 00000000..ca452bc0 --- /dev/null +++ b/src/object/object_type.cpp @@ -0,0 +1,236 @@ +/* + * This file is part of the Colobot: Gold Edition source code + * Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam + * http://epsitec.ch; http://colobot.info; http://github.com/colobot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#include "object/object_type.h" + +#include + +bool IsValidObjectTypeId(int id) +{ + static const std::unordered_set validIds{ + OBJECT_NULL, + OBJECT_PORTICO, + OBJECT_BASE, + OBJECT_DERRICK, + OBJECT_FACTORY, + OBJECT_STATION, + OBJECT_CONVERT, + OBJECT_REPAIR, + OBJECT_TOWER, + OBJECT_NEST, + OBJECT_RESEARCH, + OBJECT_RADAR, + OBJECT_ENERGY, + OBJECT_LABO, + OBJECT_NUCLEAR, + OBJECT_START, + OBJECT_END, + OBJECT_INFO, + OBJECT_PARA, + OBJECT_TARGET1, + OBJECT_TARGET2, + OBJECT_SAFE, + OBJECT_HUSTON, + OBJECT_DESTROYER, + OBJECT_STONE, + OBJECT_URANIUM, + OBJECT_METAL, + OBJECT_POWER, + OBJECT_ATOMIC, + OBJECT_BULLET, + OBJECT_BBOX, + OBJECT_TNT, + OBJECT_MARKPOWER, + OBJECT_MARKSTONE, + OBJECT_MARKURANIUM, + OBJECT_MARKKEYa, + OBJECT_MARKKEYb, + OBJECT_MARKKEYc, + OBJECT_MARKKEYd, + OBJECT_BOMB, + OBJECT_WINFIRE, + OBJECT_SHOW, + OBJECT_BAG, + OBJECT_PLANT0, + OBJECT_PLANT1, + OBJECT_PLANT2, + OBJECT_PLANT3, + OBJECT_PLANT4, + OBJECT_PLANT5, + OBJECT_PLANT6, + OBJECT_PLANT7, + OBJECT_PLANT8, + OBJECT_PLANT9, + OBJECT_PLANT10, + OBJECT_PLANT11, + OBJECT_PLANT12, + OBJECT_PLANT13, + OBJECT_PLANT14, + OBJECT_PLANT15, + OBJECT_PLANT16, + OBJECT_PLANT17, + OBJECT_PLANT18, + OBJECT_PLANT19, + OBJECT_TREE0, + OBJECT_TREE1, + OBJECT_TREE2, + OBJECT_TREE3, + OBJECT_TREE4, + OBJECT_TREE5, + OBJECT_MOBILEwt, + OBJECT_MOBILEtt, + OBJECT_MOBILEft, + OBJECT_MOBILEit, + OBJECT_MOBILErp, + OBJECT_MOBILEst, + OBJECT_MOBILEwa, + OBJECT_MOBILEta, + OBJECT_MOBILEfa, + OBJECT_MOBILEia, + OBJECT_MOBILEwc, + OBJECT_MOBILEtc, + OBJECT_MOBILEfc, + OBJECT_MOBILEic, + OBJECT_MOBILEwi, + OBJECT_MOBILEti, + OBJECT_MOBILEfi, + OBJECT_MOBILEii, + OBJECT_MOBILEws, + OBJECT_MOBILEts, + OBJECT_MOBILEfs, + OBJECT_MOBILEis, + OBJECT_MOBILErt, + OBJECT_MOBILErc, + OBJECT_MOBILErr, + OBJECT_MOBILErs, + OBJECT_MOBILEsa, + OBJECT_MOBILEtg, + OBJECT_MOBILEdr, + OBJECT_CONTROLLER, + OBJECT_MOBILEwb, + OBJECT_MOBILEtb, + OBJECT_MOBILEfb, + OBJECT_MOBILEib, + OBJECT_MOBILEpr, + OBJECT_WAYPOINT, + OBJECT_FLAGb, + OBJECT_FLAGr, + OBJECT_FLAGg, + OBJECT_FLAGy, + OBJECT_FLAGv, + OBJECT_KEYa, + OBJECT_KEYb, + OBJECT_KEYc, + OBJECT_KEYd, + OBJECT_HUMAN, + OBJECT_TOTO, + OBJECT_TECH, + OBJECT_BARRIER0, + OBJECT_BARRIER1, + OBJECT_BARRIER2, + OBJECT_BARRIER3, + OBJECT_BARRICADE0, + OBJECT_BARRICADE1, + OBJECT_MOTHER, + OBJECT_EGG, + OBJECT_ANT, + OBJECT_SPIDER, + OBJECT_BEE, + OBJECT_WORM, + OBJECT_RUINmobilew1, + OBJECT_RUINmobilew2, + OBJECT_RUINmobilet1, + OBJECT_RUINmobilet2, + OBJECT_RUINmobiler1, + OBJECT_RUINmobiler2, + OBJECT_RUINfactory, + OBJECT_RUINdoor, + OBJECT_RUINsupport, + OBJECT_RUINradar, + OBJECT_RUINconvert, + OBJECT_RUINbase, + OBJECT_RUINhead, + OBJECT_TEEN0, + OBJECT_TEEN1, + OBJECT_TEEN2, + OBJECT_TEEN3, + OBJECT_TEEN4, + OBJECT_TEEN5, + OBJECT_TEEN6, + OBJECT_TEEN7, + OBJECT_TEEN8, + OBJECT_TEEN9, + OBJECT_TEEN10, + OBJECT_TEEN11, + OBJECT_TEEN12, + OBJECT_TEEN13, + OBJECT_TEEN14, + OBJECT_TEEN15, + OBJECT_TEEN16, + OBJECT_TEEN17, + OBJECT_TEEN18, + OBJECT_TEEN19, + OBJECT_TEEN20, + OBJECT_TEEN21, + OBJECT_TEEN22, + OBJECT_TEEN23, + OBJECT_TEEN24, + OBJECT_TEEN25, + OBJECT_TEEN26, + OBJECT_TEEN27, + OBJECT_TEEN28, + OBJECT_TEEN29, + OBJECT_TEEN30, + OBJECT_TEEN31, + OBJECT_TEEN32, + OBJECT_TEEN33, + OBJECT_TEEN34, + OBJECT_TEEN35, + OBJECT_TEEN36, + OBJECT_TEEN37, + OBJECT_TEEN38, + OBJECT_TEEN39, + OBJECT_TEEN40, + OBJECT_TEEN41, + OBJECT_TEEN42, + OBJECT_TEEN43, + OBJECT_TEEN44, + OBJECT_QUARTZ0, + OBJECT_QUARTZ1, + OBJECT_QUARTZ2, + OBJECT_QUARTZ3, + OBJECT_ROOT0, + OBJECT_ROOT1, + OBJECT_ROOT2, + OBJECT_ROOT3, + OBJECT_ROOT4, + OBJECT_ROOT5, + OBJECT_MUSHROOM1, + OBJECT_MUSHROOM2, + OBJECT_APOLLO1, + OBJECT_APOLLO2, + OBJECT_APOLLO3, + OBJECT_APOLLO4, + OBJECT_APOLLO5, + OBJECT_HOME1, + + OBJECT_MAX + }; + return validIds.count(id); +} diff --git a/src/object/object_type.h b/src/object/object_type.h index d4a8f062..7f78e304 100644 --- a/src/object/object_type.h +++ b/src/object/object_type.h @@ -248,3 +248,5 @@ struct ObjectTypeHash return std::hash()(t); } }; + +bool IsValidObjectTypeId(int id); diff --git a/src/script/scriptfunc.cpp b/src/script/scriptfunc.cpp index cc2b2bda..e4d36b0d 100644 --- a/src/script/scriptfunc.cpp +++ b/src/script/scriptfunc.cpp @@ -1565,7 +1565,7 @@ bool CScriptFunctions::rProduce(CBotVar* var, CBotVar* result, int& exception, v { power = 1.0f; } - bool exists = !std::string(GetObjectName(type)).empty(); //The object type exists in object_type.h + bool exists = IsValidObjectTypeId(type) && type != OBJECT_NULL && type != OBJECT_MAX && type != OBJECT_MOBILEpr; if (exists) { object = CObjectManager::GetInstancePointer()->CreateObject(pos, angle, type, power); From 93f3abee1ad333f9a3cc2898152adc66c86ca33a Mon Sep 17 00:00:00 2001 From: MrSimbax Date: Fri, 24 Jul 2020 12:57:45 +0200 Subject: [PATCH 50/98] Change mod version separator to dot I don't know why I put comma in there and how I didn't notice this earlier. --- src/app/modman.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/modman.cpp b/src/app/modman.cpp index 76afa079..033ae458 100644 --- a/src/app/modman.cpp +++ b/src/app/modman.cpp @@ -251,7 +251,7 @@ void CModManager::LoadModData(Mod& mod) auto major = boost::lexical_cast(line->GetParam("major")->AsInt()); auto minor = boost::lexical_cast(line->GetParam("minor")->AsInt()); auto patch = boost::lexical_cast(line->GetParam("patch")->AsInt()); - data.version = boost::algorithm::join(std::vector{ major, minor, patch }, ","); + data.version = boost::algorithm::join(std::vector{ major, minor, patch }, "."); } } From 5eebe300fc3b5aef95ca8fa8f9cdf85bdd4d3795 Mon Sep 17 00:00:00 2001 From: immibis Date: Sat, 25 Jul 2020 21:13:26 +0200 Subject: [PATCH 51/98] Support new-format text models through the same code path as old models; update Blender script (#1290) --- src/graphics/engine/oldmodelmanager.cpp | 13 ++++++++++- tools/blender-scripts.py | 30 ++++++++++++++----------- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/src/graphics/engine/oldmodelmanager.cpp b/src/graphics/engine/oldmodelmanager.cpp index ee155ce8..7207cc7b 100644 --- a/src/graphics/engine/oldmodelmanager.cpp +++ b/src/graphics/engine/oldmodelmanager.cpp @@ -57,7 +57,18 @@ bool COldModelManager::LoadModel(const std::string& fileName, bool mirrored, int if (!stream.is_open()) throw CModelIOException(std::string("Could not open file '") + fileName + "'"); - model = ModelInput::Read(stream, ModelFormat::Old); + std::string::size_type extension_index = fileName.find_last_of('.'); + if (extension_index == std::string::npos) + throw CModelIOException(std::string("Filename '") + fileName + "' has no extension"); + + std::string extension = fileName.substr(extension_index + 1); + + if (extension == "mod") + model = ModelInput::Read(stream, ModelFormat::Old); + else if (extension == "txt") + model = ModelInput::Read(stream, ModelFormat::Text); + else + throw CModelIOException(std::string("Filename '") + fileName + "' has unknown extension"); } catch (const CModelIOException& e) { diff --git a/tools/blender-scripts.py b/tools/blender-scripts.py index d2273d67..b4104793 100644 --- a/tools/blender-scripts.py +++ b/tools/blender-scripts.py @@ -8,7 +8,7 @@ bl_info = { "name": "Colobot Model Format (.txt)", "author": "TerranovaTeam", - "version": (0, 0, 2), + "version": (0, 0, 3), "blender": (2, 6, 4), "location": "File > Export > Colobot (.txt)", "description": "Export Colobot Model Format (.txt)", @@ -35,7 +35,7 @@ FUZZY_TOLERANCE = 1e-5 class ColobotError(Exception): """Exception in I/O operations""" - def __init__(self, value): + def __init__(self, value, errcode=None): self.value = value def __str__(self): return repr(self.value) @@ -199,7 +199,8 @@ def write_colobot_model(filename, model): file.write('tex1 ' + t.mat.tex1 + '\n') file.write('tex2 ' + t.mat.tex2 + '\n') file.write('var_tex2 ' + ( 'Y' if t.mat.var_tex2 else 'N' + '\n' ) ) - file.write('lod_level ' + str(t.lod_level) + '\n') + if model.version == 1: + file.write('lod_level ' + str(t.lod_level) + '\n') file.write('state ' + str(t.mat.state) + '\n') file.write('\n') @@ -281,8 +282,8 @@ def read_colobot_model(filename): if (tokens[0] != 'version'): raise ColobotError("Invalid header", "version") model.version = int(tokens[1]) - if (model.version != 1): - raise ColobotError("Unknown model file version") + if (model.version != 1 and model.version != 2): + raise ColobotError("Unknown model file version "+str(model.version)) tokens, index = token_next_line(lines, index) if (tokens[0] != 'total_triangles'): @@ -329,10 +330,13 @@ def read_colobot_model(filename): raise ColobotError("Invalid triangle", "var_tex2") t.mat.var_tex2 = tokens[1] == 'Y' - tokens, index = token_next_line(lines, index) - if (tokens[0] != 'lod_level'): - raise ColobotError("Invalid triangle", "lod_level") - t.lod_level = int(tokens[1]) + if (model.version == 1): + tokens, index = token_next_line(lines, index) + if (tokens[0] != 'lod_level'): + raise ColobotError("Invalid triangle", "lod_level") + t.lod_level = int(tokens[1]) + else: + t.lod_level = 0 # constant tokens, index = token_next_line(lines, index) if (tokens[0] != 'state'): @@ -384,9 +388,9 @@ def append_obj_to_colobot_model(obj, model, scene, defaults): t.mat.specular[3] = mat.specular_alpha if (mat.texture_slots[0] != None): - t.tex1 = bpy.path.basename(mat.texture_slots[0].texture.image.filepath) + t.mat.tex1 = bpy.path.basename(mat.texture_slots[0].texture.image.filepath) if (mat.texture_slots[1] != None): - t.tex2 = bpy.path.basename(mat.texture_slots[1].texture.image.filepath) + t.mat.tex2 = bpy.path.basename(mat.texture_slots[1].texture.image.filepath) t.var_tex2 = mat.get('var_tex2', defaults['var_tex2']) t.state = mat.get('state', defaults['state']) @@ -589,7 +593,7 @@ class ExportColobotDialog(bpy.types.Operator): write_colobot_model(EXPORT_FILEPATH, model) except ColobotError as e: - self.report({'ERROR'}, e.args.join(": ")) + self.report({'ERROR'}, ": ".join(e.args)) return {'FINISHED'} self.report({'INFO'}, 'Export OK') @@ -665,7 +669,7 @@ class ImportColobotDialog(bpy.types.Operator): obj.layers = layers except ColobotError as e: - self.report({'ERROR'}, e.args.join(": ")) + self.report({'ERROR'}, ": ".join(e.args)) return {'FINISHED'} self.report({'INFO'}, 'Import OK') From fd36ff3840a7a58e9dea4a387052f944970ff74a Mon Sep 17 00:00:00 2001 From: MrSimbax Date: Sat, 25 Jul 2020 21:20:19 +0200 Subject: [PATCH 52/98] Fix crash when changing text with UTF-8 chars The code left a byte from the previous text in CEdit UI control if the new text is shorter than the old one. So an exception was thrown because it's an invalid UTF-8 byte. --- src/ui/controls/edit.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ui/controls/edit.cpp b/src/ui/controls/edit.cpp index 62987308..570bd518 100644 --- a/src/ui/controls/edit.cpp +++ b/src/ui/controls/edit.cpp @@ -1299,7 +1299,9 @@ void CEdit::SetText(const std::string& text, bool bNew) if( m_len >= GetMaxChar() ) m_len = GetMaxChar(); m_text.resize( m_len + 1, '\0' ); + m_text[m_len] = '\0'; m_format.resize( m_len + 1, m_fontType ); + m_format[m_len] = m_fontType; font = m_fontType; j = 0; From 9e743e86afc52016cd478574ddd6a303a4eddb86 Mon Sep 17 00:00:00 2001 From: immibis Date: Sun, 26 Jul 2020 14:54:53 +0200 Subject: [PATCH 53/98] Fix crash when quick-saving with increased game speed --- src/app/app.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/app/app.cpp b/src/app/app.cpp index b5bd3ca0..f998133c 100644 --- a/src/app/app.cpp +++ b/src/app/app.cpp @@ -1060,11 +1060,9 @@ int CApplication::Run() MoveMouse(Math::Point(0.5f, 0.5f)); // center mouse on start - SystemTimeStamp *lastLoopTimeStamp = m_systemUtils->CreateTimeStamp(); + SystemTimeStamp *previousTimeStamp = m_systemUtils->CreateTimeStamp(); SystemTimeStamp *currentTimeStamp = m_systemUtils->CreateTimeStamp(); SystemTimeStamp *interpolatedTimeStamp = m_systemUtils->CreateTimeStamp(); - m_systemUtils->GetCurrentTimeStamp(lastLoopTimeStamp); - m_systemUtils->CopyTimeStamp(currentTimeStamp, lastLoopTimeStamp); while (true) { @@ -1168,11 +1166,11 @@ int CApplication::Run() // If game speed is increased then we do extra ticks per loop iteration to improve physics accuracy. int numTickSlices = static_cast(GetSimulationSpeed()); if(numTickSlices < 1) numTickSlices = 1; - m_systemUtils->CopyTimeStamp(lastLoopTimeStamp, currentTimeStamp); + m_systemUtils->CopyTimeStamp(previousTimeStamp, m_curTimeStamp); m_systemUtils->GetCurrentTimeStamp(currentTimeStamp); for(int tickSlice = 0; tickSlice < numTickSlices; tickSlice++) { - m_systemUtils->InterpolateTimeStamp(interpolatedTimeStamp, lastLoopTimeStamp, currentTimeStamp, (tickSlice+1)/static_cast(numTickSlices)); + m_systemUtils->InterpolateTimeStamp(interpolatedTimeStamp, previousTimeStamp, currentTimeStamp, (tickSlice+1)/static_cast(numTickSlices)); Event event = CreateUpdateEvent(interpolatedTimeStamp); if (event.type != EVENT_NULL && m_controller != nullptr) { @@ -1203,7 +1201,7 @@ int CApplication::Run() } end: - m_systemUtils->DestroyTimeStamp(lastLoopTimeStamp); + m_systemUtils->DestroyTimeStamp(previousTimeStamp); m_systemUtils->DestroyTimeStamp(currentTimeStamp); m_systemUtils->DestroyTimeStamp(interpolatedTimeStamp); From 9cb80daedf10955eaacdccedde6a679d29f085b3 Mon Sep 17 00:00:00 2001 From: MrSimbax Date: Mon, 27 Jul 2020 15:59:33 +0200 Subject: [PATCH 54/98] Improve sound reloading Also some minor refactoring. Since realoding may take a lot of time, modman no longer reloads the whole app on entering/leaving the screen. --- src/app/app.cpp | 5 +- src/app/modman.cpp | 78 +++++++++++++++++++------ src/app/modman.h | 32 +++++++---- src/sound/oalsound/alsound.cpp | 35 +++++------ src/sound/oalsound/alsound.h | 1 + src/sound/sound.cpp | 4 ++ src/sound/sound.h | 4 ++ src/ui/screen/screen_mod_list.cpp | 96 ++++++++++++++----------------- src/ui/screen/screen_mod_list.h | 32 +---------- 9 files changed, 157 insertions(+), 130 deletions(-) diff --git a/src/app/app.cpp b/src/app/app.cpp index 72c2c2e1..ecd8cc1b 100644 --- a/src/app/app.cpp +++ b/src/app/app.cpp @@ -520,7 +520,9 @@ bool CApplication::Create() GetLogger()->Warn("Config could not be loaded. Default values will be used!\n"); } - m_modManager->Init(); + m_modManager->FindMods(); + m_modManager->SaveMods(); + m_modManager->MountAllMods(); // Create the sound instance. #ifdef OPENAL_SOUND @@ -1551,6 +1553,7 @@ void CApplication::StartLoadingMusic() SystemTimeStamp* musicLoadStart = m_systemUtils->CreateTimeStamp(); m_systemUtils->GetCurrentTimeStamp(musicLoadStart); + m_sound->Reset(); m_sound->CacheAll(); SystemTimeStamp* musicLoadEnd = m_systemUtils->CreateTimeStamp(); diff --git a/src/app/modman.cpp b/src/app/modman.cpp index 033ae458..42ba11be 100644 --- a/src/app/modman.cpp +++ b/src/app/modman.cpp @@ -44,8 +44,11 @@ CModManager::CModManager(CApplication* app, CPathManager* pathManager) { } -void CModManager::Init() +void CModManager::FindMods() { + m_mods.clear(); + m_userChanges = false; + // Load names from the config file std::vector savedModNames; GetConfigFile().GetArrayProperty("Mods", "Names", savedModNames); @@ -103,9 +106,15 @@ void CModManager::Init() m_mods.push_back(mod); } - SaveMods(); - // Load the metadata for each mod + + // Unfortunately, the paths are distinguished by their real paths, not mount points + // So we must unmount mods temporarily + for (const auto& path : m_mountedModPaths) + { + UnmountMod(path); + } + for (auto& mod : m_mods) { MountMod(mod, "/temp/mod"); @@ -113,28 +122,30 @@ void CModManager::Init() UnmountMod(mod); } - UpdatePaths(); + // Mount back + for (const auto& path : m_mountedModPaths) + { + MountMod(path); + } } void CModManager::ReloadMods() { - UnmountAllMods(); - m_mods.clear(); - - Init(); - - // Apply the configuration + UnmountAllMountedMods(); + MountAllMods(); ReloadResources(); } void CModManager::EnableMod(size_t i) { m_mods[i].enabled = true; + m_userChanges = true; } void CModManager::DisableMod(size_t i) { m_mods[i].enabled = false; + m_userChanges = true; } size_t CModManager::MoveUp(size_t i) @@ -142,6 +153,7 @@ size_t CModManager::MoveUp(size_t i) if (i != 0) { std::swap(m_mods[i - 1], m_mods[i]); + m_userChanges = true; return i - 1; } else @@ -155,6 +167,7 @@ size_t CModManager::MoveDown(size_t i) if (i != m_mods.size() - 1) { std::swap(m_mods[i], m_mods[i + 1]); + m_userChanges = true; return i + 1; } else @@ -163,13 +176,27 @@ size_t CModManager::MoveDown(size_t i) } } -void CModManager::UpdatePaths() +bool CModManager::Changes() +{ + std::vector paths; + for (const auto& mod : m_mods) + { + if (mod.enabled) + { + paths.push_back(mod.path); + } + } + return paths != m_mountedModPaths || m_userChanges; +} + +void CModManager::MountAllMods() { for (const auto& mod : m_mods) { if (mod.enabled) { MountMod(mod); + m_mountedModPaths.push_back(mod.path); } } } @@ -192,6 +219,8 @@ void CModManager::SaveMods() GetConfigFile().SetArrayProperty("Mods", "Enabled", savedEnabled); GetConfigFile().Save(); + + m_userChanges = false; } size_t CModManager::CountMods() const @@ -296,23 +325,34 @@ void CModManager::LoadModData(Mod& mod) void CModManager::MountMod(const Mod& mod, const std::string& mountPoint) { - GetLogger()->Debug("Mounting mod: '%s' at path %s\n", mod.path.c_str(), mountPoint.c_str()); - CResourceManager::AddLocation(mod.path, true, mountPoint); + MountMod(mod.path, mountPoint); +} + +void CModManager::MountMod(const std::string& path, const std::string& mountPoint) +{ + GetLogger()->Debug("Mounting mod: '%s' at path %s\n", path.c_str(), mountPoint.c_str()); + CResourceManager::AddLocation(path, true, mountPoint); } void CModManager::UnmountMod(const Mod& mod) { - if (CResourceManager::LocationExists(mod.path)) + UnmountMod(mod.path); +} + +void CModManager::UnmountMod(const std::string& path) +{ + if (CResourceManager::LocationExists(path)) { - GetLogger()->Debug("Unmounting mod: '%s'\n", mod.path.c_str()); - CResourceManager::RemoveLocation(mod.path); + GetLogger()->Debug("Unmounting mod: '%s'\n", path.c_str()); + CResourceManager::RemoveLocation(path); } } -void CModManager::UnmountAllMods() +void CModManager::UnmountAllMountedMods() { - for (const auto& mod : m_mods) + for (const auto& path : m_mountedModPaths) { - UnmountMod(mod); + UnmountMod(path); } + m_mountedModPaths.clear(); } diff --git a/src/app/modman.h b/src/app/modman.h index a8af565e..09f8b0aa 100644 --- a/src/app/modman.h +++ b/src/app/modman.h @@ -51,21 +51,17 @@ struct Mod * The order matters since the order in which files are loaded matters, * because some files can be overwritten. * - * The changes in the list do not immediately apply - * and will be lost after the \ref ReloadMods call if they were not - * saved beforehand with \ref SaveMods. - * - * The changes are also lost to mods which are no longer found in the search paths. + * The changes in the list do not immediately apply. */ class CModManager { public: CModManager(CApplication* app, CPathManager* pathManager); - //! Loads mods without resource reloading; should be called only once after creation - void Init(); - //! Finds all the mods along with their metadata + void FindMods(); + + //! Applies the current configuration and reloads the application void ReloadMods(); //! Removes a mod from the list of loaded mods @@ -80,6 +76,9 @@ public: //! Moves the selected mod down in the list so that it's loaded later than others, returns the new index size_t MoveDown(size_t i); + //! Checks if the list of currently used mods differs from the current configuration or there were changes made by the user + bool Changes(); + //! Saves the current configuration of mods to the config file void SaveMods(); @@ -93,8 +92,8 @@ public: const std::vector& GetMods() const; private: - //! Updates the paths in Path Manager according to the current mod configuration - void UpdatePaths(); + // Allow access to MountAllMods() as CApplication doesn't want to reload itself during initialization + friend CApplication; //! Reloads application resources so the enabled mods are applied void ReloadResources(); @@ -102,13 +101,24 @@ private: //! Load mod data into mod void LoadModData(Mod& mod); + //! Updates the paths in Path Manager according to the current mod configuration + void MountAllMods(); + void MountMod(const Mod& mod, const std::string& mountPoint = ""); + void MountMod(const std::string& path, const std::string& mountPoint = ""); void UnmountMod(const Mod& mod); - void UnmountAllMods(); + void UnmountMod(const std::string& path); + void UnmountAllMountedMods(); private: CApplication* m_app; CPathManager* m_pathManager; + //! Paths to mods already in the virtual filesystem + std::vector m_mountedModPaths; + + //! List of mods std::vector m_mods; + + bool m_userChanges = false; }; diff --git a/src/sound/oalsound/alsound.cpp b/src/sound/oalsound/alsound.cpp index f27a462b..26006198 100644 --- a/src/sound/oalsound/alsound.cpp +++ b/src/sound/oalsound/alsound.cpp @@ -47,22 +47,7 @@ void CALSound::CleanUp() if (m_enabled) { GetLogger()->Info("Unloading files and closing device...\n"); - StopAll(); - StopMusic(); - - m_channels.clear(); - - m_currentMusic.reset(); - - m_oldMusic.clear(); - - m_previousMusic.music.reset(); - - m_sounds.clear(); - - m_music.clear(); - - m_enabled = false; + Reset(); alcDestroyContext(m_context); alcCloseDevice(m_device); @@ -99,6 +84,24 @@ bool CALSound::Create() return true; } +void CALSound::Reset() +{ + StopAll(); + StopMusic(); + + m_channels.clear(); + + m_currentMusic.reset(); + + m_oldMusic.clear(); + + m_previousMusic.music.reset(); + + m_sounds.clear(); + + m_music.clear(); +} + bool CALSound::GetEnable() { return m_enabled; diff --git a/src/sound/oalsound/alsound.h b/src/sound/oalsound/alsound.h index 6f76c268..75e3d7f6 100644 --- a/src/sound/oalsound/alsound.h +++ b/src/sound/oalsound/alsound.h @@ -84,6 +84,7 @@ public: ~CALSound(); bool Create() override; + void Reset() override; bool Cache(SoundType, const std::string &) override; void CacheMusic(const std::string &) override; bool IsCached(SoundType) override; diff --git a/src/sound/sound.cpp b/src/sound/sound.cpp index 1cc23c4b..87d7266c 100644 --- a/src/sound/sound.cpp +++ b/src/sound/sound.cpp @@ -52,6 +52,10 @@ void CSoundInterface::CacheAll() } } +void CSoundInterface::Reset() +{ +} + bool CSoundInterface::Cache(SoundType sound, const std::string &file) { return true; diff --git a/src/sound/sound.h b/src/sound/sound.h index 78a5449d..314eb856 100644 --- a/src/sound/sound.h +++ b/src/sound/sound.h @@ -72,6 +72,10 @@ public: */ void CacheAll(); + /** Stop all sounds and music and clean cache. + */ + virtual void Reset(); + /** Function called to cache sound effect file. * This function is called by plugin interface for each file. * \param sound - id of a file, will be used to identify sound files diff --git a/src/ui/screen/screen_mod_list.cpp b/src/ui/screen/screen_mod_list.cpp index f151f781..856f2a20 100644 --- a/src/ui/screen/screen_mod_list.cpp +++ b/src/ui/screen/screen_mod_list.cpp @@ -36,6 +36,8 @@ #include "math/func.h" +#include "sound/sound.h" + #include "ui/controls/button.h" #include "ui/controls/edit.h" #include "ui/controls/interface.h" @@ -64,9 +66,6 @@ void CScreenModList::CreateInterface() Math::Point pos, ddim; std::string name; - m_changes = false; - ApplyChanges(); - // Display the window pos.x = 0.10f; pos.y = 0.10f; @@ -104,8 +103,6 @@ void CScreenModList::CreateInterface() pli->SetState(STATE_SHADOW); pli->SetState(STATE_EXTEND); - UpdateModList(); - // Displays the mod details pos.x = ox+sx*9.5f; pos.y = oy+sy*10.5f; @@ -124,8 +121,6 @@ void CScreenModList::CreateInterface() pe->SetEditCap(false); // just to see pe->SetHighlightCap(true); - UpdateModDetails(); - pos = pli->GetPos(); ddim = pli->GetDim(); @@ -148,8 +143,6 @@ void CScreenModList::CreateInterface() pe->SetEditCap(false); // just to see pe->SetHighlightCap(true); - UpdateModSummary(); - // Apply button pos.x = ox+sx*13.75f; pos.y = oy+sy*2; @@ -158,16 +151,12 @@ void CScreenModList::CreateInterface() pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_MODS_APPLY); pb->SetState(STATE_SHADOW); - UpdateApplyButton(); - // Display the enable/disable button pos.x -= dim.x*2.3f; ddim.x = dim.x*2.0f; pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_MOD_ENABLE_OR_DISABLE); pb->SetState(STATE_SHADOW); - UpdateEnableDisableButton(); - // Display the move up button pos.x -= dim.x*0.8f; pos.y = oy+sy*2.48; @@ -181,8 +170,6 @@ void CScreenModList::CreateInterface() pb = pw->CreateButton(pos, ddim, 50, EVENT_INTERFACE_MOD_MOVE_DOWN); pb->SetState(STATE_SHADOW); - UpdateUpDownButtons(); - // Display the refresh button pos.x -= dim.x*1.3f; pos.y = oy+sy*2; @@ -207,6 +194,9 @@ void CScreenModList::CreateInterface() pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_BACK); pb->SetState(STATE_SHADOW); + FindMods(); + UpdateAll(); + // Background SetBackground("textures/interface/interface.png"); CreateVersionDisplay(); @@ -231,7 +221,7 @@ bool CScreenModList::EventProcess(const Event &event) event.type == EVENT_INTERFACE_BACK || (event.type == EVENT_KEY_DOWN && event.GetData()->key == KEY(ESCAPE))) { - if (m_changes) + if (m_modManager->Changes()) { m_dialog->StartQuestion(RT_DIALOG_CHANGES_QUESTION, true, true, false, [this]() @@ -241,14 +231,11 @@ bool CScreenModList::EventProcess(const Event &event) }, [this]() { - m_changes = false; // do not save changes on "No" - ApplyChanges(); CloseWindow(); }); } else { - ApplyChanges(); CloseWindow(); } return false; @@ -278,7 +265,6 @@ bool CScreenModList::EventProcess(const Event &event) } UpdateModList(); UpdateEnableDisableButton(); - m_changes = true; UpdateApplyButton(); break; @@ -286,7 +272,6 @@ bool CScreenModList::EventProcess(const Event &event) m_modSelectedIndex = m_modManager->MoveUp(m_modSelectedIndex); UpdateModList(); UpdateUpDownButtons(); - m_changes = true; UpdateApplyButton(); break; @@ -294,20 +279,21 @@ bool CScreenModList::EventProcess(const Event &event) m_modSelectedIndex = m_modManager->MoveDown(m_modSelectedIndex); UpdateModList(); UpdateUpDownButtons(); - m_changes = true; UpdateApplyButton(); break; case EVENT_INTERFACE_MODS_REFRESH: + // Apply any changes before refresh so that the config file + // is better synchronized with the state of the game case EVENT_INTERFACE_MODS_APPLY: ApplyChanges(); - // Update the whole UI - UpdateModList(); - UpdateModSummary(); - UpdateModDetails(); - UpdateEnableDisableButton(); - UpdateApplyButton(); - UpdateUpDownButtons(); + UpdateAll(); + // Start playing the main menu music again + if (!m_app->GetSound()->IsPlayingMusic()) + { + m_app->GetSound()->PlayMusic("music/Intro1.ogg", false); + m_app->GetSound()->CacheMusic("music/Intro2.ogg"); + } break; case EVENT_INTERFACE_MODS_DIR: @@ -341,19 +327,19 @@ bool CScreenModList::EventProcess(const Event &event) return false; } +void CScreenModList::FindMods() +{ + m_modManager->FindMods(); + if (m_modManager->CountMods() != 0) + { + m_modSelectedIndex = Math::Clamp(m_modSelectedIndex, static_cast(0), m_modManager->CountMods() - 1); + } +} + void CScreenModList::ApplyChanges() { - if (m_changes) - { - m_changes = false; - m_modManager->SaveMods(); - } - + m_modManager->SaveMods(); m_modManager->ReloadMods(); - - m_empty = (m_modManager->CountMods() == 0); - - m_modSelectedIndex = Math::Clamp(m_modSelectedIndex, static_cast(0), m_modManager->CountMods() - 1); } void CScreenModList::CloseWindow() @@ -361,6 +347,16 @@ void CScreenModList::CloseWindow() m_main->ChangePhase(PHASE_MAIN_MENU); } +void CScreenModList::UpdateAll() +{ + UpdateModList(); + UpdateModDetails(); + UpdateModSummary(); + UpdateEnableDisableButton(); + UpdateApplyButton(); + UpdateUpDownButtons(); +} + void CScreenModList::UpdateModList() { CWindow* pw = static_cast(m_interface->SearchControl(EVENT_WINDOW5)); @@ -371,16 +367,16 @@ void CScreenModList::UpdateModList() pl->Flush(); - if (m_empty) + if (m_modManager->CountMods() == 0) { return; } - auto mods = m_modManager->GetMods(); + const auto& mods = m_modManager->GetMods(); for (size_t i = 0; i < mods.size(); ++i) { const auto& mod = mods[i]; - auto name = mod.data.displayName; + const auto& name = mod.data.displayName; pl->SetItemName(i, name); pl->SetCheck(i, mod.enabled); pl->SetEnable(i, true); @@ -398,7 +394,7 @@ void CScreenModList::UpdateModDetails() CEdit* pe = static_cast(pw->SearchControl(EVENT_INTERFACE_MOD_DETAILS)); if (pe == nullptr) return; - if (m_empty) + if (m_modManager->CountMods() == 0) { pe->SetText("No information"); return; @@ -475,7 +471,7 @@ void CScreenModList::UpdateModSummary() std::string noSummary; GetResource(RES_TEXT, RT_MOD_NO_SUMMARY, noSummary); - if (m_empty) + if (m_modManager->CountMods() == 0) { pe->SetText(noSummary); return; @@ -503,7 +499,7 @@ void CScreenModList::UpdateEnableDisableButton() std::string buttonName{}; - if (m_empty) + if (m_modManager->CountMods() == 0) { pb->ClearState(STATE_ENABLE); @@ -536,13 +532,7 @@ void CScreenModList::UpdateApplyButton() CButton* pb = static_cast(pw->SearchControl(EVENT_INTERFACE_MODS_APPLY)); if (pb == nullptr) return; - if (m_empty) - { - pb->ClearState(STATE_ENABLE); - return; - } - - if (m_changes) + if (m_modManager->Changes()) { pb->SetState(STATE_ENABLE); } @@ -563,7 +553,7 @@ void CScreenModList::UpdateUpDownButtons() CButton* pb_down = static_cast(pw->SearchControl(EVENT_INTERFACE_MOD_MOVE_DOWN)); if (pb_down == nullptr) return; - if (m_empty) + if (m_modManager->CountMods() == 0) { pb_up->ClearState(STATE_ENABLE); pb_down->ClearState(STATE_ENABLE); diff --git a/src/ui/screen/screen_mod_list.h b/src/ui/screen/screen_mod_list.h index 639fd775..ca2c130b 100644 --- a/src/ui/screen/screen_mod_list.h +++ b/src/ui/screen/screen_mod_list.h @@ -33,34 +33,6 @@ namespace Ui /** * \class CScreenModList * \brief This class is the front-end for the \ref CModManager. - * - * \section Assumptions Assumptions - * - * It assumes the user is changing something in the mods folders while the screen is visible, - * e.g. removing them or adding more. For this reason, the mods are always reloaded after the user - * lefts the screen, possibly after asking the user if their changes should be saved. They are also reloaded - * when the user opens the screen to avoid weird situations like "the mod is no longer there but in theory - * it's still in the game's memory even if it's not visible on the list". - * - * Unsafe changes, like removing a mod which is still enabled, are a sole responsibility of the user and - * we basically can't guarantee the game will behave properly in such cases even when they happen while - * this screen is visible. - * - * \section Features UI Features - * - * The user can reorder mods with appropriate buttons and enable/disable them. To avoid reloading - * the resources after every change, the changes are not immediate. The resources are reloaded in the - * cases described above and also after using the Apply or Refresh buttons. The only technical - * difference between them is that the Refresh button is always enabled, but Apply is only enabled - * if the user made any changes in the list by using the UI. The reason is, again, to avoid dealing with - * weird situations like described above. - * - * The UI also shows the selected mod metadata like description, version, etc. - * - * There is also a button which will try to open the default web browser with the Workshop website, - * where the user can search for new mods. - * - * For convenience, also a button opening a saves/mods folder is provided. */ class CScreenModList : public CScreen { @@ -71,9 +43,11 @@ public: bool EventProcess(const Event &event) override; protected: + void FindMods(); void ApplyChanges(); void CloseWindow(); + void UpdateAll(); void UpdateModList(); void UpdateModDetails(); void UpdateModSummary(); @@ -87,8 +61,6 @@ protected: CModManager* m_modManager; size_t m_modSelectedIndex = 0; - bool m_changes = false; - bool m_empty = true; }; } // namespace Ui From 4780716c180d942c44148404c5da220f6bacd3ed Mon Sep 17 00:00:00 2001 From: Fiftytwo Date: Thu, 30 Jul 2020 03:27:39 +0200 Subject: [PATCH 55/98] Update translation files --- po/cs.po | 15 +++++++++++++++ po/de.po | 15 +++++++++++++++ po/fr.po | 15 +++++++++++++++ po/pl.po | 15 +++++++++++++++ po/pt.po | 15 +++++++++++++++ po/ru.po | 15 +++++++++++++++ 6 files changed, 90 insertions(+) diff --git a/po/cs.po b/po/cs.po index 175ab412..c4e7d157 100644 --- a/po/cs.po +++ b/po/cs.po @@ -32,6 +32,9 @@ msgstr "Chybí \"]\"" msgid "%s: %d pts" msgstr "%s: %d bodů" +msgid "+\\Missions with bonus content and optional challenges" +msgstr "" + msgid "..behind" msgstr "...za sebou" @@ -901,6 +904,9 @@ msgstr "Mise" msgid "Missions on this planet:" msgstr "Mise na této planetě:" +msgid "Missions+" +msgstr "Mise+" + msgid "Missions\\Select mission" msgstr "Mise\\Vyberte misi" @@ -1465,6 +1471,15 @@ msgstr "Zvukové efekty:\\Hlasitost motorů, hlasů, střelby, atd." msgid "Sound\\Music and game sound volume" msgstr "Zvuk\\Hlasitost hudby a zvukových efektů" +msgid "Space Explorer\\Disables astronaut abilities" +msgstr "" + +msgid "Space Programmer\\Disables radio-control" +msgstr "" + +msgid "Space Researcher\\Disables using all previously researched technologies" +msgstr "" + msgid "Spaceship" msgstr "Raketa" diff --git a/po/de.po b/po/de.po index 8afe0c8b..8b083c40 100644 --- a/po/de.po +++ b/po/de.po @@ -33,6 +33,9 @@ msgstr "Es fehlt eine geschlossene eckige Klammer \" ] \"" msgid "%s: %d pts" msgstr "" +msgid "+\\Missions with bonus content and optional challenges" +msgstr "" + msgid "..behind" msgstr "..hinten" @@ -917,6 +920,9 @@ msgstr "Missionen" msgid "Missions on this planet:" msgstr "Liste der Missionen des Planeten:" +msgid "Missions+" +msgstr "Missionen+" + msgid "Missions\\Select mission" msgstr "Missionen\\Aufbruch ins Weltall" @@ -1482,6 +1488,15 @@ msgstr "Geräusche:\\Lautstärke Motoren, Stimmen, usw." msgid "Sound\\Music and game sound volume" msgstr "Geräusche\\Lautstärke Geräusche und Musik" +msgid "Space Explorer\\Disables astronaut abilities" +msgstr "" + +msgid "Space Programmer\\Disables radio-control" +msgstr "" + +msgid "Space Researcher\\Disables using all previously researched technologies" +msgstr "" + msgid "Spaceship" msgstr "Raumschiff" diff --git a/po/fr.po b/po/fr.po index 2bfb0c04..6d6ad1a5 100644 --- a/po/fr.po +++ b/po/fr.po @@ -32,6 +32,9 @@ msgstr "\" ] \" manquant" msgid "%s: %d pts" msgstr "%s: %d points" +msgid "+\\Missions with bonus content and optional challenges" +msgstr "" + msgid "..behind" msgstr "..derrière" @@ -919,6 +922,9 @@ msgstr "Missions" msgid "Missions on this planet:" msgstr "Liste des missions du chapitre :" +msgid "Missions+" +msgstr "Missions+" + msgid "Missions\\Select mission" msgstr "Missions\\La grande aventure" @@ -1484,6 +1490,15 @@ msgstr "Sons :\\Volume des moteurs, voix, etc." msgid "Sound\\Music and game sound volume" msgstr "Son\\Volumes des sons & musiques" +msgid "Space Explorer\\Disables astronaut abilities" +msgstr "" + +msgid "Space Programmer\\Disables radio-control" +msgstr "" + +msgid "Space Researcher\\Disables using all previously researched technologies" +msgstr "" + msgid "Spaceship" msgstr "Vaisseau spatial" diff --git a/po/pl.po b/po/pl.po index 3cef57ef..be906bf6 100644 --- a/po/pl.po +++ b/po/pl.po @@ -31,6 +31,9 @@ msgstr "Brak \" ] \"" msgid "%s: %d pts" msgstr "%s: %d pkt" +msgid "+\\Missions with bonus content and optional challenges" +msgstr "" + msgid "..behind" msgstr "..za" @@ -900,6 +903,9 @@ msgstr "Misje" msgid "Missions on this planet:" msgstr "Misje na tej planecie:" +msgid "Missions+" +msgstr "Misje+" + msgid "Missions\\Select mission" msgstr "Misje\\Wybierz misję" @@ -1464,6 +1470,15 @@ msgstr "Efekty dźwiękowe:\\Głośność silników, głosów, strzałów, itp." msgid "Sound\\Music and game sound volume" msgstr "Dźwięk\\Głośność muzyki i dźwięków gry" +msgid "Space Explorer\\Disables astronaut abilities" +msgstr "" + +msgid "Space Programmer\\Disables radio-control" +msgstr "" + +msgid "Space Researcher\\Disables using all previously researched technologies" +msgstr "" + msgid "Spaceship" msgstr "Statek kosmiczny" diff --git a/po/pt.po b/po/pt.po index 9baba2a9..726cf37b 100644 --- a/po/pt.po +++ b/po/pt.po @@ -29,6 +29,9 @@ msgstr "\" ] \" faltando" msgid "%s: %d pts" msgstr "" +msgid "+\\Missions with bonus content and optional challenges" +msgstr "" + msgid "..behind" msgstr "..atrás" @@ -914,6 +917,9 @@ msgstr "Missões" msgid "Missions on this planet:" msgstr "Lista de missões neste planeta:" +msgid "Missions+" +msgstr "Missões+" + msgid "Missions\\Select mission" msgstr "Missões\\Selecione uma missão" @@ -1479,6 +1485,15 @@ msgstr "Efeitos sonoros:\\Volume dos motores, voz, tiros, etc." msgid "Sound\\Music and game sound volume" msgstr "Som\\Volume do som das músicas e do jogo" +msgid "Space Explorer\\Disables astronaut abilities" +msgstr "" + +msgid "Space Programmer\\Disables radio-control" +msgstr "" + +msgid "Space Researcher\\Disables using all previously researched technologies" +msgstr "" + msgid "Spaceship" msgstr "Nave espacial" diff --git a/po/ru.po b/po/ru.po index 4e3f371b..5451d249 100644 --- a/po/ru.po +++ b/po/ru.po @@ -31,6 +31,9 @@ msgstr "Отсутствует \"]\" " msgid "%s: %d pts" msgstr "" +msgid "+\\Missions with bonus content and optional challenges" +msgstr "" + msgid "..behind" msgstr "Сзади" @@ -923,6 +926,9 @@ msgstr "Миссии" msgid "Missions on this planet:" msgstr "Миссии на этой планете:" +msgid "Missions+" +msgstr "Миссии+" + msgid "Missions\\Select mission" msgstr "Миссии\\Выбор миссии" @@ -1494,6 +1500,15 @@ msgstr "Общий звук:\\Гормкость двигателя, голос msgid "Sound\\Music and game sound volume" msgstr "Звук\\Громкость музыки и звуков" +msgid "Space Explorer\\Disables astronaut abilities" +msgstr "" + +msgid "Space Programmer\\Disables radio-control" +msgstr "" + +msgid "Space Researcher\\Disables using all previously researched technologies" +msgstr "" + msgid "Spaceship" msgstr "Космический корабль" From 25a8d7b5b53cd8a55c812d01d544380fa04e805c Mon Sep 17 00:00:00 2001 From: Fiftytwo Date: Thu, 30 Jul 2020 03:48:31 +0200 Subject: [PATCH 56/98] Move flatground scan button from Sniffers to Builders --- src/ui/object_interface.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/ui/object_interface.cpp b/src/ui/object_interface.cpp index abee9b2b..4a101fc9 100644 --- a/src/ui/object_interface.cpp +++ b/src/ui/object_interface.cpp @@ -1117,14 +1117,7 @@ bool CObjectInterface::CreateInterface(bool bSelect) pw->CreateButton(pos, dim, 40, EVENT_OBJECT_SEARCH); DefaultEnter(pw, EVENT_OBJECT_SEARCH); - if ( m_main->IsBuildingEnabled(BUILD_GFLAT) ) - { - pos.x = ox+sx*9.0f; - pos.y = oy+sy*0.5f; - pw->CreateButton(pos, dim, 111, EVENT_OBJECT_GFLAT); - } - - pos.x = ox+sx*10.1f; + pos.x = ox+sx*9.0f; pos.y = oy+sy*0.5f; pw->CreateButton(pos, dim, 11, EVENT_OBJECT_DELSEARCH); } @@ -1500,6 +1493,12 @@ bool CObjectInterface::CreateInterface(bool bSelect) pw->CreateButton(pos, ddim, 128+41, EVENT_OBJECT_BDESTROYER); DeadInterface(pw, EVENT_OBJECT_BDESTROYER, m_main->CanBuild(OBJECT_DESTROYER, m_object->GetTeam())); + if ( m_main->IsBuildingEnabled(BUILD_GFLAT) ) + { + pos.x = ox+sx*9.0f; + pos.y = oy+sy*0.5f; + pw->CreateButton(pos, dim, 64+47, EVENT_OBJECT_GFLAT); + } } UpdateInterface(); m_lastUpdateTime = 0.0f; From e63afb34611e54b75b86eb577b84a2eee9abad27 Mon Sep 17 00:00:00 2001 From: Fiftytwo Date: Thu, 30 Jul 2020 04:21:35 +0200 Subject: [PATCH 57/98] Add WayPoint animation in deletemark --- src/object/task/taskdeletemark.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/object/task/taskdeletemark.cpp b/src/object/task/taskdeletemark.cpp index b45bd7a0..4b9ced5e 100644 --- a/src/object/task/taskdeletemark.cpp +++ b/src/object/task/taskdeletemark.cpp @@ -23,6 +23,7 @@ #include "common/global.h" #include "graphics/engine/particle.h" +#include "graphics/engine/pyro_manager.h" #include "graphics/engine/terrain.h" #include "level/robotmain.h" @@ -88,6 +89,6 @@ void CTaskDeleteMark::DeleteMark() if (obj != nullptr) { - CObjectManager::GetInstancePointer()->DeleteObject(obj); + m_engine->GetPyroManager()->Create(Gfx::PT_WPCHECK, obj); } } From a92fa950e2991c51bd47ead6323f34305928aee4 Mon Sep 17 00:00:00 2001 From: Fiftytwo Date: Thu, 30 Jul 2020 11:03:12 +0200 Subject: [PATCH 58/98] Make Sniffers able to plant flags --- src/object/task/taskflag.cpp | 76 ++++++++++++++++++++++++++++++++++-- src/ui/object_interface.cpp | 38 +++++++++++++++++- 2 files changed, 109 insertions(+), 5 deletions(-) diff --git a/src/object/task/taskflag.cpp b/src/object/task/taskflag.cpp index c9790ebf..b2872159 100644 --- a/src/object/task/taskflag.cpp +++ b/src/object/task/taskflag.cpp @@ -61,6 +61,24 @@ bool CTaskFlag::EventProcess(const Event &event) m_time += event.rTime; + ObjectType type = m_object->GetType(); + if ( type == OBJECT_MOBILEfs || + type == OBJECT_MOBILEts || + type == OBJECT_MOBILEws || + type == OBJECT_MOBILEis ) + { + float angle = 110.0f*Math::PI/180.0f; + float diff = -10.0f*Math::PI/180.0f; + if ( m_time <= 0.5f ) + { + m_object->SetPartRotationZ(1, angle+diff*m_time*2.0f); + } + else if ( m_time >= 1.5f && m_time < 2.0f ) + { + m_object->SetPartRotationZ(1, angle+diff*(2.0f-m_time)*2.0f); + } + } + return true; } @@ -104,7 +122,32 @@ Error CTaskFlag::Start(TaskFlagOrder order, int rank) m_bError = false; - m_motion->SetAction(MHS_FLAG); // sets/removes flag + switch ( m_object->GetType() ) // sets/removes flag + { + case OBJECT_HUMAN: + case OBJECT_TECH: + m_motion->SetAction(MHS_FLAG); + break; + + case OBJECT_MOBILEws: + case OBJECT_MOBILEts: + case OBJECT_MOBILEfs: + case OBJECT_MOBILEis: + { + int i = m_sound->Play(SOUND_MANIP, m_object->GetPosition(), 0.0f, 0.3f, true); + m_sound->AddEnvelope(i, 0.5f, 1.0f, 0.1f, SOPER_CONTINUE); + m_sound->AddEnvelope(i, 0.5f, 1.0f, 0.3f, SOPER_CONTINUE); + m_sound->AddEnvelope(i, 0.0f, 0.3f, 0.1f, SOPER_CONTINUE); + m_sound->AddEnvelope(i, 0.0f, 0.3f, 1.0f, SOPER_CONTINUE); + m_sound->AddEnvelope(i, 0.5f, 1.0f, 0.1f, SOPER_CONTINUE); + m_sound->AddEnvelope(i, 0.5f, 1.0f, 0.3f, SOPER_CONTINUE); + m_sound->AddEnvelope(i, 0.0f, 0.3f, 0.1f, SOPER_STOP); + break; + } + + default: + break; + } m_camera->StartCentering(m_object, Math::PI*0.3f, 99.9f, 0.0f, 0.5f); return ERR_OK; @@ -127,7 +170,23 @@ Error CTaskFlag::IsEnded() bool CTaskFlag::Abort() { - m_motion->SetAction(-1); + switch ( m_object->GetType() ) + { + case OBJECT_HUMAN: + case OBJECT_TECH: + m_motion->SetAction(-1); + break; + + case OBJECT_MOBILEws: + case OBJECT_MOBILEts: + case OBJECT_MOBILEfs: + case OBJECT_MOBILEis: + m_object->SetPartRotationZ(1, 110.0f*Math::PI/180.0f); + break; + + default: + break; + } m_camera->StopCentering(m_object, 2.0f); return true; } @@ -190,7 +249,18 @@ Error CTaskFlag::CreateFlag(int rank) }; Math::Matrix* mat = m_object->GetWorldMatrix(0); - Math::Vector pos = Transform(*mat, Math::Vector(4.0f, 0.0f, 0.0f)); + Math::Vector pos; + switch ( m_object->GetType() ) + { + case OBJECT_HUMAN: + case OBJECT_TECH: + pos = Transform(*mat, Math::Vector(4.0f, 0.0f, 0.0f)); + break; + + default: + pos = Transform(*mat, Math::Vector(6.0f, 0.0f, 0.0f)); + break; + } CObject* pObj = SearchNearest(pos, OBJECT_NULL); if ( pObj != nullptr ) diff --git a/src/ui/object_interface.cpp b/src/ui/object_interface.cpp index 4a101fc9..24a9969c 100644 --- a/src/ui/object_interface.cpp +++ b/src/ui/object_interface.cpp @@ -1120,6 +1120,36 @@ bool CObjectInterface::CreateInterface(bool bSelect) pos.x = ox+sx*9.0f; pos.y = oy+sy*0.5f; pw->CreateButton(pos, dim, 11, EVENT_OBJECT_DELSEARCH); + + if ( m_main->IsBuildingEnabled(BUILD_FLAG) ) + { + pos.x = ox+sx*10.1f; + pos.y = oy+sy*0.5f; + pw->CreateButton(pos, dim, 64+54, EVENT_OBJECT_FCREATE); + + pos.x = ox+sx*11.1f; + pos.y = oy+sy*0.5f; + pw->CreateButton(pos, dim, 64+55, EVENT_OBJECT_FDELETE); + + ddim.x = dim.x*0.4f; + ddim.y = dim.y*0.4f; + pos.x = ox+sx*10.1f; + pos.y = oy+sy*2.0f-ddim.y; + pc = pw->CreateColor(pos, ddim, -1, EVENT_OBJECT_FCOLORb); + pc->SetColor(Gfx::Color(0.28f, 0.56f, 1.0f, 0.0f)); + pos.x += ddim.x; + pc = pw->CreateColor(pos, ddim, -1, EVENT_OBJECT_FCOLORr); + pc->SetColor(Gfx::Color(1.0f, 0.0f, 0.0f, 0.0f)); + pos.x += ddim.x; + pc = pw->CreateColor(pos, ddim, -1, EVENT_OBJECT_FCOLORg); + pc->SetColor(Gfx::Color(0.0f, 0.8f, 0.0f, 0.0f)); + pos.x += ddim.x; + pc = pw->CreateColor(pos, ddim, -1, EVENT_OBJECT_FCOLORy); + pc->SetColor(Gfx::Color(1.0f, 0.93f, 0.0f, 0.0f)); //0x00ffec00 + pos.x += ddim.x; + pc = pw->CreateColor(pos, ddim, -1, EVENT_OBJECT_FCOLORv); + pc->SetColor(Gfx::Color(0.82f, 0.004f, 0.99f, 0.0f)); //0x00d101fe + } } if ( type == OBJECT_MOBILErt && // Terraformer? @@ -1796,8 +1826,12 @@ void CObjectInterface::UpdateInterface() EnableInterface(pw, EVENT_OBJECT_BDESTROYER,bEnable); } - if ( type == OBJECT_HUMAN || // builder? - type == OBJECT_TECH ) + if ( type == OBJECT_HUMAN || // can create flags? + type == OBJECT_TECH || + type == OBJECT_MOBILEfs || + type == OBJECT_MOBILEts || + type == OBJECT_MOBILEws || + type == OBJECT_MOBILEis ) { CheckInterface(pw, EVENT_OBJECT_FCOLORb, m_flagColor==0); CheckInterface(pw, EVENT_OBJECT_FCOLORr, m_flagColor==1); From 2023756023a589d5753cc1b27a3aa1a11d0ebccb Mon Sep 17 00:00:00 2001 From: Fiftytwo Date: Thu, 30 Jul 2020 11:11:51 +0200 Subject: [PATCH 59/98] Fix factory() being able to produce non-bot units --- src/level/robotmain.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/level/robotmain.cpp b/src/level/robotmain.cpp index 523f69c6..9c3323c5 100644 --- a/src/level/robotmain.cpp +++ b/src/level/robotmain.cpp @@ -5957,6 +5957,8 @@ Error CRobotMain::CanFactoryError(ObjectType type, int team) if (type == OBJECT_MOBILEst && !IsResearchDone(RESEARCH_SUBM, team)) return ERR_BUILD_DISABLED; if (type == OBJECT_MOBILEtg && !IsResearchDone(RESEARCH_TARGET, team)) return ERR_BUILD_RESEARCH; + if (tool == ToolType::Other && drive == DriveType::Other && type != OBJECT_MOBILEtg) return ERR_WRONG_OBJ; + return ERR_OK; } From 33b7c893cb63a24a4633cea81fda0e564710d705 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Kapu=C5=9Bci=C5=84ski?= Date: Fri, 31 Jul 2020 22:01:33 +0200 Subject: [PATCH 60/98] Allow length of the light direction vector to influence strength of the light source. This fixes the issue with objects and terrain being darker than they should be. As it turns out, most levels have not normalized light direction which happens to make light brighter and this is the expected result. To keep in line with GL14 engine, newer engines should use the length of the vector to make light brighter. --- src/graphics/opengl/shaders/gl21/fs_normal.glsl | 4 ++-- src/graphics/opengl/shaders/gl33/fs_normal.glsl | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/graphics/opengl/shaders/gl21/fs_normal.glsl b/src/graphics/opengl/shaders/gl21/fs_normal.glsl index 77402258..1aeffcbe 100644 --- a/src/graphics/opengl/shaders/gl21/fs_normal.glsl +++ b/src/graphics/opengl/shaders/gl21/fs_normal.glsl @@ -84,8 +84,8 @@ void main() { LightParams light = uni_Light[i]; - vec3 lightDirection = normalize(light.Position.xyz); - vec3 reflectAxis = normalize(lightDirection + camera); + vec3 lightDirection = light.Position.xyz; + vec3 reflectAxis = normalize(normalize(lightDirection) + camera); float diffuseComponent = clamp(dot(normal, lightDirection), 0.0f, 1.0f); float specularComponent = pow(clamp(dot(normal, reflectAxis), 0.0f, 1.0f), 10.0f); diff --git a/src/graphics/opengl/shaders/gl33/fs_normal.glsl b/src/graphics/opengl/shaders/gl33/fs_normal.glsl index 7b498723..be58f4fd 100644 --- a/src/graphics/opengl/shaders/gl33/fs_normal.glsl +++ b/src/graphics/opengl/shaders/gl33/fs_normal.glsl @@ -83,8 +83,8 @@ void main() for (int i = 0; i < uni_LightCount; i++) { - vec3 lightDirection = normalize(uni_Light[i].Position.xyz); - vec3 reflectAxis = normalize(lightDirection + camera); + vec3 lightDirection = uni_Light[i].Position.xyz; + vec3 reflectAxis = normalize(normalize(lightDirection) + camera); ambient += uni_Light[i].Ambient; diffuse += clamp(dot(normal, lightDirection), 0.0f, 1.0f) From 4c14050b27f6f2a54ea7b552afceb6929e7bc2b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Kapu=C5=9Bci=C5=84ski?= Date: Fri, 31 Jul 2020 22:04:47 +0200 Subject: [PATCH 61/98] Fixed mipmaps being outdates after texture update. --- src/graphics/opengl/gl33device.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/graphics/opengl/gl33device.cpp b/src/graphics/opengl/gl33device.cpp index 2ca1aa4f..bd26d35b 100644 --- a/src/graphics/opengl/gl33device.cpp +++ b/src/graphics/opengl/gl33device.cpp @@ -886,6 +886,8 @@ void CGL33Device::UpdateTexture(const Texture& texture, Math::IntPoint offset, I glTexSubImage2D(GL_TEXTURE_2D, 0, offset.x, offset.y, texData.actualSurface->w, texData.actualSurface->h, texData.sourceFormat, GL_UNSIGNED_BYTE, texData.actualSurface->pixels); + glGenerateMipmap(GL_TEXTURE_2D); + SDL_FreeSurface(texData.convertedSurface); } From b9305dfd45cc0e0b13e9b755cd4e47aaf788b8b0 Mon Sep 17 00:00:00 2001 From: Fiftytwo Date: Sat, 8 Aug 2020 14:34:21 +0200 Subject: [PATCH 62/98] Fix Mushroom SatCom links --- src/script/cbottoken.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/script/cbottoken.cpp b/src/script/cbottoken.cpp index 4cdae229..fa58a1a6 100644 --- a/src/script/cbottoken.cpp +++ b/src/script/cbottoken.cpp @@ -243,8 +243,8 @@ std::string GetHelpFilename(ObjectType type) if ( type == OBJECT_PLANT0 ) helpfile = "object/bush"; if ( type == OBJECT_ROOT5 ) helpfile = "object/gravi"; if ( type == OBJECT_QUARTZ0 ) helpfile = "object/crystal"; - if ( type == OBJECT_MUSHROOM1 ) helpfile = "object/gremush"; - if ( type == OBJECT_MUSHROOM2 ) helpfile = "object/bromush"; + if ( type == OBJECT_MUSHROOM1 ) helpfile = "object/bromush"; + if ( type == OBJECT_MUSHROOM2 ) helpfile = "object/gremush"; if (helpfile.empty()) return ""; From 4bb6f9f1b340c584cc843d610cc0382c7b5e1559 Mon Sep 17 00:00:00 2001 From: tomangelo2 Date: Sat, 8 Aug 2020 15:41:07 +0200 Subject: [PATCH 63/98] Remove unnecessary warning if there is no fonts.ini file --- src/graphics/engine/text.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/graphics/engine/text.cpp b/src/graphics/engine/text.cpp index 9ff42bb6..e0cf9c82 100644 --- a/src/graphics/engine/text.cpp +++ b/src/graphics/engine/text.cpp @@ -194,7 +194,7 @@ bool CText::Create() CFontLoader fontLoader; if (!fontLoader.Init()) { - GetLogger()->Warn("Error on parsing fonts config file: failed to open file\n"); + GetLogger()->Debug("Error on parsing fonts config file: failed to open file\n"); } if (TTF_Init() != 0) { From 56c99e741e530ff5b422c7e64921adebe458dabf Mon Sep 17 00:00:00 2001 From: Fiftytwo Date: Sat, 8 Aug 2020 20:51:56 +0200 Subject: [PATCH 64/98] Make Vault buildable --- po/colobot.pot | 2 +- po/cs.po | 9 ++++++--- po/de.po | 9 ++++++--- po/fr.po | 9 ++++++--- po/pl.po | 9 ++++++--- po/pt.po | 9 ++++++--- po/ru.po | 9 ++++++--- src/common/event.cpp | 2 +- src/common/event.h | 2 +- src/common/restext.cpp | 2 +- src/level/build_type.h | 3 ++- src/level/parser/parserparam.cpp | 1 + src/level/robotmain.cpp | 1 + src/object/task/taskbuild.cpp | 2 ++ src/script/scriptfunc.cpp | 1 + src/ui/object_interface.cpp | 16 ++++++++-------- 16 files changed, 55 insertions(+), 31 deletions(-) diff --git a/po/colobot.pot b/po/colobot.pot index 9803a978..b1b3518d 100644 --- a/po/colobot.pot +++ b/po/colobot.pot @@ -769,7 +769,7 @@ msgstr "" msgid "Build a exchange post" msgstr "" -msgid "Build a destroyer" +msgid "Build a vault" msgstr "" msgid "Show if the ground is flat" diff --git a/po/cs.po b/po/cs.po index c4e7d157..34d59283 100644 --- a/po/cs.po +++ b/po/cs.po @@ -200,9 +200,6 @@ msgstr "Postavit obrannou věž" msgid "Build a derrick" msgstr "Postavit vrtnou věž" -msgid "Build a destroyer" -msgstr "Postavit drtič" - msgid "Build a exchange post" msgstr "Postavit komunikační stanici" @@ -275,6 +272,9 @@ msgstr "Vyrobit pásový kanón" msgid "Build a tracked sniffer" msgstr "Vyrobit pásový detektor" +msgid "Build a vault" +msgstr "" + msgid "Build a wheeled builder" msgstr "" @@ -1936,3 +1936,6 @@ msgstr "colobot.info" msgid "epsitec.com" msgstr "epsitec.com" + +#~ msgid "Build a destroyer" +#~ msgstr "Postavit drtič" diff --git a/po/de.po b/po/de.po index 8b083c40..727ba367 100644 --- a/po/de.po +++ b/po/de.po @@ -201,9 +201,6 @@ msgstr "Baut einen Geschützturm" msgid "Build a derrick" msgstr "Baut einen Bohrturm" -msgid "Build a destroyer" -msgstr "Baue einen Zerstörer" - msgid "Build a exchange post" msgstr "Baut einen Infoserver" @@ -276,6 +273,9 @@ msgstr "Baut einen Kettenshooter" msgid "Build a tracked sniffer" msgstr "Baut einen Kettenschnüffler" +msgid "Build a vault" +msgstr "" + msgid "Build a wheeled builder" msgstr "" @@ -1967,6 +1967,9 @@ msgstr "epsitec.com" #~ msgid "3D sound\\3D positioning of the sound" #~ msgstr "3D-Geräusche\\Orten der Geräusche im Raum" +#~ msgid "Build a destroyer" +#~ msgstr "Baue einen Zerstörer" + #~ msgid "Building too close" #~ msgstr "Gebäude zu nahe" diff --git a/po/fr.po b/po/fr.po index 6d6ad1a5..506ba564 100644 --- a/po/fr.po +++ b/po/fr.po @@ -203,9 +203,6 @@ msgstr "Construire une tour" msgid "Build a derrick" msgstr "Construire un derrick" -msgid "Build a destroyer" -msgstr "Construire un destructeur" - msgid "Build a exchange post" msgstr "Construire une station relais" @@ -278,6 +275,9 @@ msgstr "Fabriquer un tireur à chenilles" msgid "Build a tracked sniffer" msgstr "Fabriquer un renifleur à chenilles" +msgid "Build a vault" +msgstr "" + msgid "Build a wheeled builder" msgstr "" @@ -1966,6 +1966,9 @@ msgstr "epsitec.com" #~ msgid "3D sound\\3D positioning of the sound" #~ msgstr "Bruitages 3D\\Positionnement sonore dans l'espace" +#~ msgid "Build a destroyer" +#~ msgstr "Construire un destructeur" + #~ msgid "Building too close" #~ msgstr "Bâtiment trop proche" diff --git a/po/pl.po b/po/pl.po index be906bf6..92c209a6 100644 --- a/po/pl.po +++ b/po/pl.po @@ -199,9 +199,6 @@ msgstr "Zbuduj wieżę obronną" msgid "Build a derrick" msgstr "Zbuduj kopalnię" -msgid "Build a destroyer" -msgstr "Zbuduj niszczarkę" - msgid "Build a exchange post" msgstr "Zbuduj stację przekaźnikową" @@ -274,6 +271,9 @@ msgstr "Zbuduj działo na gąsienicach" msgid "Build a tracked sniffer" msgstr "Zbuduj szperacz na gąsienicach" +msgid "Build a vault" +msgstr "" + msgid "Build a wheeled builder" msgstr "" @@ -1945,6 +1945,9 @@ msgstr "epsitec.com" #~ msgid "3D sound\\3D positioning of the sound" #~ msgstr "Dźwięk 3D\\Przestrzenne pozycjonowanie dźwięków" +#~ msgid "Build a destroyer" +#~ msgstr "Zbuduj niszczarkę" + #~ msgid "Building too close" #~ msgstr "Budynek za blisko" diff --git a/po/pt.po b/po/pt.po index 726cf37b..ebef8681 100644 --- a/po/pt.po +++ b/po/pt.po @@ -197,9 +197,6 @@ msgstr "Construir uma torre de defesa" msgid "Build a derrick" msgstr "Construir um extrator" -msgid "Build a destroyer" -msgstr "Construir um destruidor" - msgid "Build a exchange post" msgstr "Construir um posto de troca" @@ -272,6 +269,9 @@ msgstr "Construir um atirador com esteiras" msgid "Build a tracked sniffer" msgstr "Construir um farejador com esteiras" +msgid "Build a vault" +msgstr "" + msgid "Build a wheeled builder" msgstr "" @@ -1964,6 +1964,9 @@ msgstr "epsitec.com" #~ msgid "3D sound\\3D positioning of the sound" #~ msgstr "Bruitages 3D\\Positionnement sonore dans l'espace" +#~ msgid "Build a destroyer" +#~ msgstr "Construir um destruidor" + #~ msgid "Building too close" #~ msgstr "Bâtiment trop proche" diff --git a/po/ru.po b/po/ru.po index 5451d249..a0f0d658 100644 --- a/po/ru.po +++ b/po/ru.po @@ -200,9 +200,6 @@ msgstr "Построить защитную башню" msgid "Build a derrick" msgstr "Построить буровую вышку" -msgid "Build a destroyer" -msgstr "Построить уничтожитель" - msgid "Build a exchange post" msgstr "Построить пост по обмену сообщениями" @@ -275,6 +272,9 @@ msgstr "Собрать гусеничного стрелка" msgid "Build a tracked sniffer" msgstr "Собрать гусеничного искателя" +msgid "Build a vault" +msgstr "" + msgid "Build a wheeled builder" msgstr "" @@ -1980,6 +1980,9 @@ msgstr "epsitec.com" #~ msgid "3D sound\\3D positioning of the sound" #~ msgstr "3D-звук\\Стерео звук" +#~ msgid "Build a destroyer" +#~ msgstr "Построить уничтожитель" + #~ msgid "Building too close" #~ msgstr "Здание слишком близко" diff --git a/src/common/event.cpp b/src/common/event.cpp index f03830f3..1a6ee43c 100644 --- a/src/common/event.cpp +++ b/src/common/event.cpp @@ -410,7 +410,7 @@ void InitializeEventTypeTexts() EVENT_TYPE_TEXT[EVENT_OBJECT_BNUCLEAR] = "EVENT_OBJECT_BNUCLEAR"; EVENT_TYPE_TEXT[EVENT_OBJECT_BPARA] = "EVENT_OBJECT_BPARA"; EVENT_TYPE_TEXT[EVENT_OBJECT_BINFO] = "EVENT_OBJECT_BINFO"; - EVENT_TYPE_TEXT[EVENT_OBJECT_BDESTROYER] = "EVENT_OBJECT_BDESTROYER"; + EVENT_TYPE_TEXT[EVENT_OBJECT_BSAFE] = "EVENT_OBJECT_BSAFE"; EVENT_TYPE_TEXT[EVENT_OBJECT_GFLAT] = "EVENT_OBJECT_GFLAT"; EVENT_TYPE_TEXT[EVENT_OBJECT_FCREATE] = "EVENT_OBJECT_FCREATE"; EVENT_TYPE_TEXT[EVENT_OBJECT_FDELETE] = "EVENT_OBJECT_FDELETE"; diff --git a/src/common/event.h b/src/common/event.h index 9eace389..1bdb06e4 100644 --- a/src/common/event.h +++ b/src/common/event.h @@ -474,7 +474,7 @@ enum EventType EVENT_OBJECT_BNUCLEAR = 1060, EVENT_OBJECT_BPARA = 1061, EVENT_OBJECT_BINFO = 1062, - EVENT_OBJECT_BDESTROYER = 1063, + EVENT_OBJECT_BSAFE = 1063, EVENT_OBJECT_GFLAT = 1070, EVENT_OBJECT_FCREATE = 1071, EVENT_OBJECT_FDELETE = 1072, diff --git a/src/common/restext.cpp b/src/common/restext.cpp index 36cebc45..a12aa67f 100644 --- a/src/common/restext.cpp +++ b/src/common/restext.cpp @@ -347,7 +347,7 @@ void InitializeRestext() stringsEvent[EVENT_OBJECT_BNUCLEAR] = TR("Build a nuclear power plant"); stringsEvent[EVENT_OBJECT_BPARA] = TR("Build a lightning conductor"); stringsEvent[EVENT_OBJECT_BINFO] = TR("Build a exchange post"); - stringsEvent[EVENT_OBJECT_BDESTROYER] = TR("Build a destroyer"); + stringsEvent[EVENT_OBJECT_BSAFE] = TR("Build a vault"); stringsEvent[EVENT_OBJECT_GFLAT] = TR("Show if the ground is flat"); stringsEvent[EVENT_OBJECT_FCREATE] = TR("Plant a flag"); stringsEvent[EVENT_OBJECT_FDELETE] = TR("Remove a flag"); diff --git a/src/level/build_type.h b/src/level/build_type.h index cabe4159..26c595e4 100644 --- a/src/level/build_type.h +++ b/src/level/build_type.h @@ -41,7 +41,8 @@ enum BuildType BUILD_LABO = (1<<10), //! < AutoLab BUILD_PARA = (1<<11), //! < PowerCaptor BUILD_INFO = (1<<12), //! < ExchangePost - BUILD_DESTROYER = (1<<13), //! < Destroyer + BUILD_SAFE = (1<<13), //! < Vault + BUILD_DESTROYER = (1<<14), //! < Destroyer BUILD_GFLAT = (1<<16), //! < checking flat ground BUILD_FLAG = (1<<17) //! < putting / removing flags }; diff --git a/src/level/parser/parserparam.cpp b/src/level/parser/parserparam.cpp index 083ce47a..159ab5f7 100644 --- a/src/level/parser/parserparam.cpp +++ b/src/level/parser/parserparam.cpp @@ -885,6 +885,7 @@ int CLevelParserParam::ToBuildFlag(std::string value) if (value == "AutoLab" ) return BUILD_LABO; if (value == "PowerCaptor" ) return BUILD_PARA; if (value == "ExchangePost" ) return BUILD_INFO; + if (value == "Vault" ) return BUILD_SAFE; if (value == "Destroyer" ) return BUILD_DESTROYER; if (value == "FlatGround" ) return BUILD_GFLAT; if (value == "Flag" ) return BUILD_FLAG; diff --git a/src/level/robotmain.cpp b/src/level/robotmain.cpp index 9c3323c5..25262737 100644 --- a/src/level/robotmain.cpp +++ b/src/level/robotmain.cpp @@ -5887,6 +5887,7 @@ bool CRobotMain::IsBuildingEnabled(ObjectType type) if(type == OBJECT_NUCLEAR) return IsBuildingEnabled(BUILD_NUCLEAR); if(type == OBJECT_INFO) return IsBuildingEnabled(BUILD_INFO); if(type == OBJECT_PARA) return IsBuildingEnabled(BUILD_PARA); + if(type == OBJECT_SAFE) return IsBuildingEnabled(BUILD_SAFE); if(type == OBJECT_DESTROYER) return IsBuildingEnabled(BUILD_DESTROYER); return false; diff --git a/src/object/task/taskbuild.cpp b/src/object/task/taskbuild.cpp index 763b8655..b1ee0037 100644 --- a/src/object/task/taskbuild.cpp +++ b/src/object/task/taskbuild.cpp @@ -111,6 +111,7 @@ void CTaskBuild::CreateBuilding(Math::Vector pos, float angle, bool trainer) if ( m_type == OBJECT_NUCLEAR ) m_buildingHeight = 40.0f; if ( m_type == OBJECT_PARA ) m_buildingHeight = 68.0f; if ( m_type == OBJECT_INFO ) m_buildingHeight = 19.0f; + if ( m_type == OBJECT_SAFE ) m_buildingHeight = 16.0f; if ( m_type == OBJECT_DESTROYER) m_buildingHeight = 35.0f; if ( m_type == OBJECT_HUSTON ) m_buildingHeight = 45.0f; m_buildingHeight *= 0.25f; @@ -682,6 +683,7 @@ Error CTaskBuild::FlatFloor() if ( m_type == OBJECT_NUCLEAR ) radius = 20.0f; if ( m_type == OBJECT_PARA ) radius = 20.0f; if ( m_type == OBJECT_INFO ) radius = 5.0f; + if ( m_type == OBJECT_SAFE ) radius = 20.0f; if ( m_type == OBJECT_DESTROYER) radius = 20.0f; //if ( radius == 0.0f ) return ERR_UNKNOWN; diff --git a/src/script/scriptfunc.cpp b/src/script/scriptfunc.cpp index ba217a55..b16db045 100644 --- a/src/script/scriptfunc.cpp +++ b/src/script/scriptfunc.cpp @@ -3369,6 +3369,7 @@ void CScriptFunctions::Init() CBotProgram::DefineNum("BuildAutoLab", BUILD_LABO); CBotProgram::DefineNum("BuildPowerCaptor", BUILD_PARA); CBotProgram::DefineNum("BuildExchangePost", BUILD_INFO); + CBotProgram::DefineNum("BuildVault", BUILD_SAFE); CBotProgram::DefineNum("BuildDestroyer", BUILD_DESTROYER); CBotProgram::DefineNum("FlatGround", BUILD_GFLAT); CBotProgram::DefineNum("UseFlags", BUILD_FLAG); diff --git a/src/ui/object_interface.cpp b/src/ui/object_interface.cpp index 24a9969c..a24da9ba 100644 --- a/src/ui/object_interface.cpp +++ b/src/ui/object_interface.cpp @@ -536,9 +536,9 @@ bool CObjectInterface::EventProcess(const Event &event) { err = m_taskExecutor->StartTaskBuild(OBJECT_INFO); } - if ( action == EVENT_OBJECT_BDESTROYER ) + if ( action == EVENT_OBJECT_BSAFE ) { - err = m_taskExecutor->StartTaskBuild(OBJECT_DESTROYER); + err = m_taskExecutor->StartTaskBuild(OBJECT_SAFE); } if ( action == EVENT_OBJECT_GFLAT ) @@ -1065,8 +1065,8 @@ bool CObjectInterface::CreateInterface(bool bSelect) pos.x = ox+sx*5.4f; pos.y = oy+sy*0.1f; - pw->CreateButton(pos, ddim, 128+41, EVENT_OBJECT_BDESTROYER); - DeadInterface(pw, EVENT_OBJECT_BDESTROYER, m_main->CanBuild(OBJECT_DESTROYER, m_object->GetTeam())); + pw->CreateButton(pos, ddim, 128+47, EVENT_OBJECT_BSAFE); + DeadInterface(pw, EVENT_OBJECT_BSAFE, m_main->CanBuild(OBJECT_SAFE, m_object->GetTeam())); if ( m_main->IsBuildingEnabled(BUILD_GFLAT) ) { @@ -1520,8 +1520,8 @@ bool CObjectInterface::CreateInterface(bool bSelect) DeadInterface(pw, EVENT_OBJECT_BPARA, m_main->CanBuild(OBJECT_PARA, m_object->GetTeam())); pos.x = ox+sx*5.4f; - pw->CreateButton(pos, ddim, 128+41, EVENT_OBJECT_BDESTROYER); - DeadInterface(pw, EVENT_OBJECT_BDESTROYER, m_main->CanBuild(OBJECT_DESTROYER, m_object->GetTeam())); + pw->CreateButton(pos, ddim, 128+47, EVENT_OBJECT_BSAFE); + DeadInterface(pw, EVENT_OBJECT_BSAFE, m_main->CanBuild(OBJECT_SAFE, m_object->GetTeam())); if ( m_main->IsBuildingEnabled(BUILD_GFLAT) ) { @@ -1823,7 +1823,7 @@ void CObjectInterface::UpdateInterface() EnableInterface(pw, EVENT_OBJECT_BNUCLEAR, bEnable); EnableInterface(pw, EVENT_OBJECT_BPARA, bEnable); EnableInterface(pw, EVENT_OBJECT_BINFO, bEnable); - EnableInterface(pw, EVENT_OBJECT_BDESTROYER,bEnable); + EnableInterface(pw, EVENT_OBJECT_BSAFE, bEnable); } if ( type == OBJECT_HUMAN || // can create flags? @@ -1900,7 +1900,7 @@ void CObjectInterface::UpdateInterface() pb->SetState(STATE_VISIBLE, m_buildInterface); pb = static_cast< CButton* >(pw->SearchControl(EVENT_OBJECT_BPARA)); pb->SetState(STATE_VISIBLE, m_buildInterface); - pb = static_cast< CButton* >(pw->SearchControl(EVENT_OBJECT_BDESTROYER)); + pb = static_cast< CButton* >(pw->SearchControl(EVENT_OBJECT_BSAFE)); pb->SetState(STATE_VISIBLE, m_buildInterface); pb = static_cast< CButton* >(pw->SearchControl(EVENT_OBJECT_BINFO)); pb->SetState(STATE_VISIBLE, m_buildInterface); From 4c1d3eecd1206e3323d4f4ac2e95ee62e8a018b2 Mon Sep 17 00:00:00 2001 From: Fiftytwo Date: Sat, 15 Aug 2020 03:31:17 +0200 Subject: [PATCH 65/98] Add flag() and deflag() CBOT functions --- src/object/interface/trace_drawing_object.cpp | 18 ++-- src/object/interface/trace_drawing_object.h | 37 +++---- src/script/cbottoken.cpp | 15 ++- src/script/scriptfunc.cpp | 98 +++++++++++++++++++ src/script/scriptfunc.h | 2 + 5 files changed, 140 insertions(+), 30 deletions(-) diff --git a/src/object/interface/trace_drawing_object.cpp b/src/object/interface/trace_drawing_object.cpp index c8fdab98..b0c8343d 100644 --- a/src/object/interface/trace_drawing_object.cpp +++ b/src/object/interface/trace_drawing_object.cpp @@ -27,21 +27,22 @@ std::string TraceColorName(TraceColor color) { switch(color) { + case TraceColor::Blue: return "Blue"; + case TraceColor::Red: return "Red"; + case TraceColor::Green: return "Green"; + case TraceColor::Yellow: return "Yellow"; + case TraceColor::Violet: return "Violet"; case TraceColor::White: return "White"; case TraceColor::Black: return "Black"; case TraceColor::Gray: return "Gray"; case TraceColor::LightGray: return "LightGray"; - case TraceColor::Red: return "Red"; case TraceColor::Pink: return "Pink"; case TraceColor::Purple: return "Purple"; case TraceColor::Orange: return "Orange"; - case TraceColor::Yellow: return "Yellow"; case TraceColor::Beige: return "Beige"; case TraceColor::Brown: return "Brown"; case TraceColor::Skin: return "Skin"; - case TraceColor::Green: return "Green"; case TraceColor::LightGreen: return "LightGreen"; - case TraceColor::Blue: return "Blue"; case TraceColor::LightBlue: return "LightBlue"; case TraceColor::RedArrow: return "RedArrow"; case TraceColor::BlackArrow: return "BlackArrow"; @@ -55,21 +56,22 @@ Gfx::Color TraceColorColor(TraceColor color) { switch(color) { + case TraceColor::Blue: return Gfx::Color(0.000f, 0.000f, 0.753f, 1.0f); + case TraceColor::Red: return Gfx::Color(1.000f, 0.000f, 0.000f, 1.0f); + case TraceColor::Green: return Gfx::Color(0.000f, 0.627f, 0.000f, 1.0f); + case TraceColor::Yellow: return Gfx::Color(1.000f, 1.000f, 0.000f, 1.0f); + case TraceColor::Violet: return Gfx::Color(0.820f, 0.000f, 0.997f, 1.0f); case TraceColor::White: return Gfx::Color(1.000f, 1.000f, 1.000f, 1.0f); case TraceColor::Black: return Gfx::Color(0.000f, 0.000f, 0.000f, 1.0f); case TraceColor::Gray: return Gfx::Color(0.549f, 0.549f, 0.549f, 1.0f); case TraceColor::LightGray: return Gfx::Color(0.753f, 0.753f, 0.753f, 1.0f); - case TraceColor::Red: return Gfx::Color(1.000f, 0.000f, 0.000f, 1.0f); case TraceColor::Pink: return Gfx::Color(1.000f, 0.627f, 0.753f, 1.0f); case TraceColor::Purple: return Gfx::Color(0.878f, 0.000f, 0.753f, 1.0f); case TraceColor::Orange: return Gfx::Color(1.000f, 0.627f, 0.000f, 1.0f); - case TraceColor::Yellow: return Gfx::Color(1.000f, 1.000f, 0.000f, 1.0f); case TraceColor::Beige: return Gfx::Color(0.878f, 0.753f, 0.000f, 1.0f); case TraceColor::Brown: return Gfx::Color(0.627f, 0.361f, 0.000f, 1.0f); case TraceColor::Skin: return Gfx::Color(0.961f, 0.839f, 0.714f, 1.0f); - case TraceColor::Green: return Gfx::Color(0.000f, 0.627f, 0.000f, 1.0f); case TraceColor::LightGreen: return Gfx::Color(0.000f, 1.000f, 0.000f, 1.0f); - case TraceColor::Blue: return Gfx::Color(0.000f, 0.000f, 0.753f, 1.0f); case TraceColor::LightBlue: return Gfx::Color(0.000f, 0.871f, 1.000f, 1.0f); case TraceColor::BlackArrow: return TraceColorColor(TraceColor::Black); case TraceColor::RedArrow: return TraceColorColor(TraceColor::Red); //TODO: We could probably have all the colors available as arrows now diff --git a/src/object/interface/trace_drawing_object.h b/src/object/interface/trace_drawing_object.h index 6dd0dda0..36e05463 100644 --- a/src/object/interface/trace_drawing_object.h +++ b/src/object/interface/trace_drawing_object.h @@ -32,24 +32,25 @@ enum class TraceColor { Default = -1, - White = 0, - Black = 1, - Gray = 2, - LightGray = 3, - Red = 4, - Pink = 5, - Purple = 6, - Orange = 7, - Yellow = 8, - Beige = 9, - Brown = 10, - Skin = 11, - Green = 12, - LightGreen = 13, - Blue = 14, - LightBlue = 15, - BlackArrow = 16, - RedArrow = 17, + Blue = 0, + Red = 1, + Green = 2, + Yellow = 3, + Violet = 4, + White = 5, + Black = 6, + Gray = 7, + LightGray = 8, + Pink = 9, + Purple = 10, + Orange = 11, + Beige = 12, + Brown = 13, + Skin = 14, + LightGreen = 15, + LightBlue = 16, + BlackArrow = 17, + RedArrow = 18, Max, }; //! Convert TraceColor to a std::string diff --git a/src/script/cbottoken.cpp b/src/script/cbottoken.cpp index fa58a1a6..8cc118f1 100644 --- a/src/script/cbottoken.cpp +++ b/src/script/cbottoken.cpp @@ -322,6 +322,8 @@ std::string GetHelpFilename(const char *token) if ( strcmp(token, "researched" ) == 0 ) helpfile = "cbot/researched"; if ( strcmp(token, "buildingenabled") == 0 ) helpfile = "cbot/buildingenabled"; if ( strcmp(token, "build" ) == 0 ) helpfile = "cbot/build"; + if ( strcmp(token, "flag" ) == 0 ) helpfile = "cbot/flag"; + if ( strcmp(token, "deflag" ) == 0 ) helpfile = "cbot/deflag"; if ( strcmp(token, "wait" ) == 0 ) helpfile = "cbot/wait"; if ( strcmp(token, "move" ) == 0 ) helpfile = "cbot/move"; if ( strcmp(token, "turn" ) == 0 ) helpfile = "cbot/turn"; @@ -344,23 +346,24 @@ std::string GetHelpFilename(const char *token) if ( strcmp(token, "topo" ) == 0 ) helpfile = "cbot/topo"; if ( strcmp(token, "message" ) == 0 ) helpfile = "cbot/message"; if ( strcmp(token, "abstime" ) == 0 ) helpfile = "cbot/abstime"; + if ( strcmp(token, "Blue" ) == 0 ) helpfile = "cbot/flag"; + if ( strcmp(token, "Red" ) == 0 ) helpfile = "cbot/flag"; + if ( strcmp(token, "Green" ) == 0 ) helpfile = "cbot/flag"; + if ( strcmp(token, "Yellow" ) == 0 ) helpfile = "cbot/flag"; + if ( strcmp(token, "Violet" ) == 0 ) helpfile = "cbot/flag"; if ( strcmp(token, "BlackArrow" ) == 0 ) helpfile = "cbot/pendown"; if ( strcmp(token, "RedArrow" ) == 0 ) helpfile = "cbot/pendown"; if ( strcmp(token, "White" ) == 0 ) helpfile = "cbot/pendown"; if ( strcmp(token, "Black" ) == 0 ) helpfile = "cbot/pendown"; if ( strcmp(token, "Gray" ) == 0 ) helpfile = "cbot/pendown"; if ( strcmp(token, "LightGray" ) == 0 ) helpfile = "cbot/pendown"; - if ( strcmp(token, "Red" ) == 0 ) helpfile = "cbot/pendown"; if ( strcmp(token, "Pink" ) == 0 ) helpfile = "cbot/pendown"; if ( strcmp(token, "Purple" ) == 0 ) helpfile = "cbot/pendown"; if ( strcmp(token, "Orange" ) == 0 ) helpfile = "cbot/pendown"; - if ( strcmp(token, "Yellow" ) == 0 ) helpfile = "cbot/pendown"; if ( strcmp(token, "Beige" ) == 0 ) helpfile = "cbot/pendown"; if ( strcmp(token, "Brown" ) == 0 ) helpfile = "cbot/pendown"; if ( strcmp(token, "Skin" ) == 0 ) helpfile = "cbot/pendown"; - if ( strcmp(token, "Green" ) == 0 ) helpfile = "cbot/pendown"; if ( strcmp(token, "LightGreen" ) == 0 ) helpfile = "cbot/pendown"; - if ( strcmp(token, "Blue" ) == 0 ) helpfile = "cbot/pendown"; if ( strcmp(token, "LightBlue" ) == 0 ) helpfile = "cbot/pendown"; if ( strcmp(token, "InFront" ) == 0 ) helpfile = "cbot/grab"; if ( strcmp(token, "Behind" ) == 0 ) helpfile = "cbot/grab"; @@ -482,6 +485,8 @@ bool IsFunction(const char *token) if ( strcmp(token, "researched" ) == 0 ) return true; if ( strcmp(token, "buildingenabled") == 0 ) return true; if ( strcmp(token, "build" ) == 0 ) return true; + if ( strcmp(token, "flag" ) == 0 ) return true; + if ( strcmp(token, "deflag" ) == 0 ) return true; if ( strcmp(token, "wait" ) == 0 ) return true; if ( strcmp(token, "move" ) == 0 ) return true; if ( strcmp(token, "turn" ) == 0 ) return true; @@ -588,6 +593,8 @@ const char* GetHelpText(const char *token) if ( strcmp(token, "researched" ) == 0 ) return "researched ( research );"; if ( strcmp(token, "buildingenabled") == 0 ) return "buildingenabled ( category );"; if ( strcmp(token, "build" ) == 0 ) return "build ( category );"; + if ( strcmp(token, "flag" ) == 0 ) return "flag ( color );"; + if ( strcmp(token, "deflag" ) == 0 ) return "deflag ( );"; if ( strcmp(token, "wait" ) == 0 ) return "wait ( time );"; if ( strcmp(token, "move" ) == 0 ) return "move ( distance );"; if ( strcmp(token, "turn" ) == 0 ) return "turn ( angle );"; diff --git a/src/script/scriptfunc.cpp b/src/script/scriptfunc.cpp index b16db045..6db8f34c 100644 --- a/src/script/scriptfunc.cpp +++ b/src/script/scriptfunc.cpp @@ -1439,6 +1439,102 @@ bool CScriptFunctions::rBuild(CBotVar* var, CBotVar* result, int& exception, voi } +// Instruction "flag(color)" + +bool CScriptFunctions::rFlag(CBotVar* var, CBotVar* result, int& exception, void* user) +{ + CScript* script = static_cast(user); + CObject* pThis = script->m_object; + ObjectType oType; + int color; + Error err; + + exception = 0; + + if ( !script->m_taskExecutor->IsForegroundTask() ) + { + oType = pThis->GetType(); + if ( oType != OBJECT_MOBILEfs && // allowed only for sniffer bots && humans + oType != OBJECT_MOBILEts && + oType != OBJECT_MOBILEws && + oType != OBJECT_MOBILEis && + oType != OBJECT_HUMAN && + oType != OBJECT_TECH ) + { + err = ERR_WRONG_BOT; // Wrong object + } + else + { + if ( var == nullptr ) + { + color = 0; + } + else + { + color = var->GetValInt(); + if ( color < 0 || color > static_cast(TraceColor::Violet) ) color = 0; + } + err = script->m_taskExecutor->StartTaskFlag(TFL_CREATE, color); + } + + if ( err != ERR_OK ) + { + script->m_taskExecutor->StopForegroundTask(); + result->SetValInt(err); // shows the error + if ( script->m_errMode == ERM_STOP ) + { + exception = err; + return false; + } + return true; + } + } + return WaitForForegroundTask(script, result, exception); +} + +// Instruction "deflag()" + +bool CScriptFunctions::rDeflag(CBotVar* var, CBotVar* result, int& exception, void* user) +{ + CScript* script = static_cast(user); + CObject* pThis = script->m_object; + ObjectType oType; + Error err; + + exception = 0; + + if ( !script->m_taskExecutor->IsForegroundTask() ) + { + oType = pThis->GetType(); + if ( oType != OBJECT_MOBILEfs && // allowed only for sniffer bots && humans + oType != OBJECT_MOBILEts && + oType != OBJECT_MOBILEws && + oType != OBJECT_MOBILEis && + oType != OBJECT_HUMAN && + oType != OBJECT_TECH ) + { + err = ERR_WRONG_BOT; // Wrong object + } + else + { + err = script->m_taskExecutor->StartTaskFlag(TFL_DELETE, 0); + } + + if ( err != ERR_OK ) + { + script->m_taskExecutor->StopForegroundTask(); + result->SetValInt(err); // shows the error + if ( script->m_errMode == ERM_STOP ) + { + exception = err; + return false; + } + return true; + } + } + return WaitForForegroundTask(script, result, exception); +} + // Compilation of the instruction "produce(pos, angle, type[, scriptName[, power]])" // or "produce(type[, power])". @@ -3437,6 +3533,8 @@ void CScriptFunctions::Init() CBotProgram::AddFunction("buildingenabled", rBuildingEnabled, cOneIntReturnBool); CBotProgram::AddFunction("build", rBuild, cOneInt); + CBotProgram::AddFunction("flag", rFlag, cGrabDrop); + CBotProgram::AddFunction("deflag", rDeflag, cNull); CBotProgram::AddFunction("retobject", rGetObject, cGetObject); CBotProgram::AddFunction("retobjectbyid", rGetObjectById, cGetObject); diff --git a/src/script/scriptfunc.h b/src/script/scriptfunc.h index 2ecbf8b2..2a2cd718 100644 --- a/src/script/scriptfunc.h +++ b/src/script/scriptfunc.h @@ -110,6 +110,8 @@ private: static bool rResearched(CBot::CBotVar* var, CBot::CBotVar* result, int& exception, void* user); static bool rBuildingEnabled(CBot::CBotVar* var, CBot::CBotVar* result, int& exception, void* user); static bool rBuild(CBot::CBotVar* var, CBot::CBotVar* result, int& exception, void* user); + static bool rFlag(CBot::CBotVar* var, CBot::CBotVar* result, int& exception, void* user); + static bool rDeflag(CBot::CBotVar* var, CBot::CBotVar* result, int& exception, void* user); static bool rProduce(CBot::CBotVar* var, CBot::CBotVar* result, int& exception, void* user); static bool rDistance(CBot::CBotVar* var, CBot::CBotVar* result, int& exception, void* user); static bool rDistance2d(CBot::CBotVar* var, CBot::CBotVar* result, int& exception, void* user); From d0961a517a6a4061874554986207e8a6674f828f Mon Sep 17 00:00:00 2001 From: melex750 Date: Sat, 15 Aug 2020 09:29:45 -0400 Subject: [PATCH 66/98] Fix abs() only working on floats --- src/CBot/stdlib/MathFunctions.cpp | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/CBot/stdlib/MathFunctions.cpp b/src/CBot/stdlib/MathFunctions.cpp index b51d5748..ebe46545 100644 --- a/src/CBot/stdlib/MathFunctions.cpp +++ b/src/CBot/stdlib/MathFunctions.cpp @@ -144,13 +144,36 @@ bool rRand(CBotVar* var, CBotVar* result, int& exception, void* user) bool rAbs(CBotVar* var, CBotVar* result, int& exception, void* user) { - float value; + switch (result->GetType()) + { + case CBotTypDouble: + *result = fabs(var->GetValDouble()); + break; + case CBotTypFloat: + *result = fabs(var->GetValFloat()); + break; + case CBotTypLong: + *result = abs(var->GetValLong()); + break; + default: + *result = abs(var->GetValInt()); + break; + } - value = var->GetValFloat(); - result->SetValFloat(fabs(value)); return true; } +CBotTypResult cAbs(CBotVar* &var, void* user) +{ + if ( var == nullptr ) return CBotTypResult(CBotErrLowParam); + if ( var->GetType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum); + + CBotTypResult returnType(var->GetType()); + var = var->GetNext(); + if ( var != nullptr ) return CBotTypResult(CBotErrOverParam); + return returnType; +} + // Instruction "floor()" bool rFloor(CBotVar* var, CBotVar* result, int& exception, void* user) @@ -209,7 +232,7 @@ void InitMathFunctions() CBotProgram::AddFunction("sqrt", rSqrt, cOneFloat); CBotProgram::AddFunction("pow", rPow, cTwoFloat); CBotProgram::AddFunction("rand", rRand, cNull); - CBotProgram::AddFunction("abs", rAbs, cOneFloat); + CBotProgram::AddFunction("abs", rAbs, cAbs); CBotProgram::AddFunction("floor", rFloor, cOneFloat); CBotProgram::AddFunction("ceil", rCeil, cOneFloat); CBotProgram::AddFunction("round", rRound, cOneFloat); From 8d5cafecb39c12522c8c8534d9acf708599c3d13 Mon Sep 17 00:00:00 2001 From: melex750 Date: Sat, 15 Aug 2020 09:41:31 -0400 Subject: [PATCH 67/98] Fix CBOT script hanging at delete() --- src/script/scriptfunc.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/script/scriptfunc.cpp b/src/script/scriptfunc.cpp index e4d36b0d..7f09ed5e 100644 --- a/src/script/scriptfunc.cpp +++ b/src/script/scriptfunc.cpp @@ -734,6 +734,9 @@ bool CScriptFunctions::rDelete(CBotVar* var, CBotVar* result, int& exception, vo } else { + CScript* script = static_cast(user); + bool deleteSelf = (obj == script->m_object); + if ( exploType != DestructionType::NoEffect && obj->Implements(ObjectInterfaceType::Destroyable) ) { dynamic_cast(obj)->DestroyObject(static_cast(exploType)); @@ -752,12 +755,13 @@ bool CScriptFunctions::rDelete(CBotVar* var, CBotVar* result, int& exception, vo } CObjectManager::GetInstancePointer()->DeleteObject(obj); } + // Returning "false" here makes sure the program doesn't try to keep executing + // if the robot just destroyed itself using delete(this.id) + // See issue #925 + return !deleteSelf; } - // Returning "false" here makes sure the program doesn't try to keep executing if the robot just destroyed itself - // using delete(this.id) - // See issue #925 - return false; + return true; } static CBotTypResult compileSearch(CBotVar* &var, void* user, CBotTypResult returnValue) From 68c254c1010c4971769e202c46f6036bef5e5f04 Mon Sep 17 00:00:00 2001 From: Fiftytwo Date: Fri, 21 Aug 2020 18:09:28 +0200 Subject: [PATCH 68/98] Update data submodule --- data | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data b/data index 611cbfdd..069fc5bd 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 611cbfdd079e97a71f97810636f2ab2358cb4eeb +Subproject commit 069fc5bd15b87aaf5b1b301a787f05a99dfc3856 From f08c67bef9bb70fa5a46ad36b966de8a954cfe2a Mon Sep 17 00:00:00 2001 From: tomangelo2 Date: Thu, 27 Aug 2020 00:28:03 +0200 Subject: [PATCH 69/98] Fix warning regarding mismatched parameter types --- src/CBot/stdlib/MathFunctions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CBot/stdlib/MathFunctions.cpp b/src/CBot/stdlib/MathFunctions.cpp index ebe46545..f6e5b484 100644 --- a/src/CBot/stdlib/MathFunctions.cpp +++ b/src/CBot/stdlib/MathFunctions.cpp @@ -153,7 +153,7 @@ bool rAbs(CBotVar* var, CBotVar* result, int& exception, void* user) *result = fabs(var->GetValFloat()); break; case CBotTypLong: - *result = abs(var->GetValLong()); + *result = labs(var->GetValLong()); break; default: *result = abs(var->GetValInt()); From a54a117ba43534340e5aa7ab35c2b55afc32c684 Mon Sep 17 00:00:00 2001 From: ccao001 <69090073+ccao001@users.noreply.github.com> Date: Sun, 30 Aug 2020 00:44:45 -0400 Subject: [PATCH 70/98] README: Add Guix GNU Guix is a transactional package manager and an advanced distribution of the GNU system that respects user freedom. Guix can be used on top of any system running the kernel Linux, or it can be used as a standalone operating system distribution for i686, x86_64, ARMv7, and AArch64 machines. In addition to standard package management features, Guix supports transactional upgrades and roll-backs, unprivileged package management, per-user profiles, and garbage collection. When used as a standalone GNU/Linux distribution, Guix offers a declarative, stateless approach to operating system configuration management. Guix is highly customizable and hackable through Guile programming interfaces and extensions to the Scheme language. --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c7d4a9a5..6e5b0f7f 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,8 @@ We provide compiled packages of most recent versions using an [automated build b On some Linux distributions there are also distribution packages available: * Debian Sid (unstable): http://packages.debian.org/sid/colobot * Arch Linux (AUR): https://aur.archlinux.org/packages/colobot-gold - * openSUSE: http://software.opensuse.org/download.html?project=games&package=colobot + * openSUSE http://software.opensuse.org/download.html?project=games&package=colobot + * Guix https://guix.gnu.org/en/packages/colobot-0.1.12-alpha/ ## Compiling and running the game From 2685a1eb6018fc1c0b7ff28187b18597d4f58671 Mon Sep 17 00:00:00 2001 From: tomangelo Date: Mon, 31 Aug 2020 13:37:45 +0200 Subject: [PATCH 71/98] Add cell capacity parameters (#1348) --- src/level/robotmain.cpp | 12 ++++++++++++ src/level/robotmain.h | 8 ++++++++ src/object/old_object.cpp | 2 +- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/level/robotmain.cpp b/src/level/robotmain.cpp index 7092b32b..619b7c7f 100644 --- a/src/level/robotmain.cpp +++ b/src/level/robotmain.cpp @@ -3150,6 +3150,8 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) m_missionType = line->GetParam("type")->AsMissionType(MISSION_NORMAL); m_globalMagnifyDamage = line->GetParam("magnifyDamage")->AsFloat(1.0f); + m_globalNuclearCapacity = line->GetParam("nuclearCapacity")->AsFloat(10.0f); + m_globalCellCapacity = line->GetParam("cellCapacity")->AsFloat(1.0f); continue; } @@ -5978,6 +5980,16 @@ float CRobotMain::GetGlobalMagnifyDamage() return m_globalMagnifyDamage; } +float CRobotMain::GetGlobalNuclearCapacity() +{ + return m_globalNuclearCapacity; +} + +float CRobotMain::GetGlobalCellCapacity() +{ + return m_globalCellCapacity; +} + // Beginning of the effect when the instruction "detect" is used. void CRobotMain::StartDetectEffect(COldObject* object, CObject* target) diff --git a/src/level/robotmain.h b/src/level/robotmain.h index 731d7a1a..8ad31cbc 100644 --- a/src/level/robotmain.h +++ b/src/level/robotmain.h @@ -468,6 +468,11 @@ public: //! Returns global magnifyDamage setting float GetGlobalMagnifyDamage(); + //! Returns global NuclearCell capacity Setting + float GetGlobalNuclearCapacity(); + //! Returns global PowerCell capacity setting + float GetGlobalCellCapacity(); + void StartDetectEffect(COldObject* object, CObject* target); //! Enable crash sphere debug rendering @@ -650,6 +655,9 @@ protected: float m_globalMagnifyDamage = 0.0f; + float m_globalNuclearCapacity = 10.0f; + float m_globalCellCapacity = 1.0f; + bool m_exitAfterMission = false; bool m_codeBattleInit = false; diff --git a/src/object/old_object.cpp b/src/object/old_object.cpp index 5fd93df8..eaffaa10 100644 --- a/src/object/old_object.cpp +++ b/src/object/old_object.cpp @@ -2500,7 +2500,7 @@ float COldObject::GetAbsTime() float COldObject::GetCapacity() { - return m_type == OBJECT_ATOMIC ? 10.0f : 1.0f; + return m_type == OBJECT_ATOMIC ? m_main->GetGlobalNuclearCapacity() : m_main->GetGlobalCellCapacity() ; } bool COldObject::IsRechargeable() From 8c6ac4cd162a13381cfe7ec792871c0db5e27ce8 Mon Sep 17 00:00:00 2001 From: Jeff Law Date: Thu, 3 Sep 2020 22:03:31 +0000 Subject: [PATCH 72/98] Fix dynamic casts to avoid gcc-11 diagnostics --- src/graphics/engine/camera.cpp | 8 ++++---- src/object/interface/carrier_object.h | 2 +- src/object/interface/powered_object.h | 10 +++++----- src/object/interface/transportable_object.h | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/graphics/engine/camera.cpp b/src/graphics/engine/camera.cpp index c55473ab..f3b96186 100644 --- a/src/graphics/engine/camera.cpp +++ b/src/graphics/engine/camera.cpp @@ -59,14 +59,14 @@ static void SetTransparency(CObject* obj, float value) if (obj->Implements(ObjectInterfaceType::Carrier)) { - CObject* cargo = dynamic_cast(obj)->GetCargo(); + CObject* cargo = dynamic_cast(*obj).GetCargo(); if (cargo != nullptr) cargo->SetTransparency(value); } if (obj->Implements(ObjectInterfaceType::Powered)) { - CObject* power = dynamic_cast(obj)->GetPower(); + CObject* power = dynamic_cast(*obj).GetPower(); if (power != nullptr) power->SetTransparency(value); } @@ -1233,7 +1233,7 @@ bool CCamera::EventFrameBack(const Event &event) bool ground = true; if (m_cameraObj->Implements(ObjectInterfaceType::Movable)) - ground = dynamic_cast(m_cameraObj)->GetPhysics()->GetLand(); + ground = dynamic_cast(*m_cameraObj).GetPhysics()->GetLand(); if ( ground ) // ground? { Math::Vector pos = lookatPt + (lookatPt - m_eyePt); @@ -1326,7 +1326,7 @@ bool CCamera::EventFrameOnBoard(const Event &event) { assert(m_cameraObj->Implements(ObjectInterfaceType::Controllable)); Math::Vector lookatPt, upVec; - dynamic_cast(m_cameraObj)->AdjustCamera(m_eyePt, m_directionH, m_directionV, lookatPt, upVec, m_type); + dynamic_cast(*m_cameraObj).AdjustCamera(m_eyePt, m_directionH, m_directionV, lookatPt, upVec, m_type); Math::Vector eye = m_effectOffset * 0.3f + m_eyePt; Math::Vector lookat = m_effectOffset * 0.3f + lookatPt; diff --git a/src/object/interface/carrier_object.h b/src/object/interface/carrier_object.h index 857ff0bf..2cbf3d73 100644 --- a/src/object/interface/carrier_object.h +++ b/src/object/interface/carrier_object.h @@ -51,5 +51,5 @@ public: inline bool IsObjectCarryingCargo(CObject* obj) { return obj->Implements(ObjectInterfaceType::Carrier) && - dynamic_cast(obj)->IsCarryingCargo(); + dynamic_cast(*obj).IsCarryingCargo(); } diff --git a/src/object/interface/powered_object.h b/src/object/interface/powered_object.h index b1652e47..3aea3296 100644 --- a/src/object/interface/powered_object.h +++ b/src/object/interface/powered_object.h @@ -61,10 +61,10 @@ inline float GetObjectEnergy(CObject* object) if (object->Implements(ObjectInterfaceType::Powered)) { - CObject* power = dynamic_cast(object)->GetPower(); + CObject* power = dynamic_cast(*object).GetPower(); if (power != nullptr && power->Implements(ObjectInterfaceType::PowerContainer)) { - energy = dynamic_cast(power)->GetEnergy(); + energy = dynamic_cast(*power).GetEnergy(); } } @@ -77,10 +77,10 @@ inline float GetObjectEnergyLevel(CObject* object) if (object->Implements(ObjectInterfaceType::Powered)) { - CObject* power = dynamic_cast(object)->GetPower(); + CObject* power = dynamic_cast(*object).GetPower(); if (power != nullptr && power->Implements(ObjectInterfaceType::PowerContainer)) { - energy = dynamic_cast(power)->GetEnergyLevel(); + energy = dynamic_cast(*power).GetEnergyLevel(); } } @@ -90,5 +90,5 @@ inline float GetObjectEnergyLevel(CObject* object) inline bool ObjectHasPowerCell(CObject* object) { return object->Implements(ObjectInterfaceType::Powered) && - dynamic_cast(object)->GetPower() != nullptr; + dynamic_cast(*object).GetPower() != nullptr; } diff --git a/src/object/interface/transportable_object.h b/src/object/interface/transportable_object.h index a45d9e0c..38e88dc5 100644 --- a/src/object/interface/transportable_object.h +++ b/src/object/interface/transportable_object.h @@ -54,5 +54,5 @@ public: inline bool IsObjectBeingTransported(CObject* obj) { return obj->Implements(ObjectInterfaceType::Transportable) && - dynamic_cast(obj)->IsBeingTransported(); + dynamic_cast(*obj).IsBeingTransported(); } From ad2e3db92fe6272f2420c90cd9859a74f344cb5c Mon Sep 17 00:00:00 2001 From: Jeff Law Date: Mon, 14 Sep 2020 19:19:16 +0000 Subject: [PATCH 73/98] Fix more dynamic casts for gcc-11 Signed-off-by: suve Jeff's patch was written for the 0.1.12 stable release. Adapted to work with the "dev" branch (as of commit 13098ee). --- src/graphics/engine/lightning.cpp | 2 +- src/graphics/engine/particle.cpp | 16 ++-- src/graphics/engine/pyro.cpp | 40 ++++---- src/level/mainmovie.cpp | 6 +- src/level/robotmain.cpp | 92 +++++++++---------- src/level/scene_conditions.cpp | 4 +- src/object/auto/autobase.cpp | 8 +- src/object/auto/autodestroyer.cpp | 2 +- src/object/auto/autoegg.cpp | 8 +- src/object/auto/autofactory.cpp | 8 +- src/object/auto/autonuclearplant.cpp | 2 +- src/object/auto/autopowercaptor.cpp | 4 +- src/object/auto/autopowerplant.cpp | 2 +- src/object/auto/autopowerstation.cpp | 4 +- src/object/auto/autorepair.cpp | 6 +- src/object/auto/autotower.cpp | 7 +- .../implementation/program_storage_impl.cpp | 8 +- .../implementation/programmable_impl.cpp | 14 +-- src/object/motion/motionant.cpp | 4 +- src/object/motion/motionspider.cpp | 4 +- src/object/motion/motionvehicle.cpp | 2 +- src/object/object_manager.cpp | 6 +- src/object/old_object.cpp | 8 +- src/object/task/taskfire.cpp | 2 +- src/object/task/taskfireant.cpp | 6 +- src/object/task/taskgoto.cpp | 2 +- src/object/task/taskmanip.cpp | 64 ++++++------- src/object/task/taskrecover.cpp | 2 +- src/object/task/taskshield.cpp | 2 +- src/object/task/taskspiderexplo.cpp | 2 +- src/object/task/tasktake.cpp | 36 ++++---- src/object/task/taskterraform.cpp | 11 ++- src/physics/physics.cpp | 54 +++++------ src/script/scriptfunc.cpp | 20 ++-- src/ui/controls/map.cpp | 4 +- src/ui/controls/target.cpp | 6 +- src/ui/displayinfo.cpp | 6 +- src/ui/displaytext.cpp | 2 +- src/ui/mainshort.cpp | 8 +- src/ui/object_interface.cpp | 4 +- 40 files changed, 244 insertions(+), 244 deletions(-) diff --git a/src/graphics/engine/lightning.cpp b/src/graphics/engine/lightning.cpp index 84a99bbc..8b101e53 100644 --- a/src/graphics/engine/lightning.cpp +++ b/src/graphics/engine/lightning.cpp @@ -323,7 +323,7 @@ CObject* CLightning::SearchObject(Math::Vector pos) if (!obj->Implements(ObjectInterfaceType::Destroyable)) continue; - float detect = m_magnetic * dynamic_cast(obj)->GetLightningHitProbability(); + float detect = m_magnetic * dynamic_cast(*obj).GetLightningHitProbability(); if (detect == 0.0f) continue; Math::Vector oPos = obj->GetPosition(); diff --git a/src/graphics/engine/particle.cpp b/src/graphics/engine/particle.cpp index 07370493..fa430488 100644 --- a/src/graphics/engine/particle.cpp +++ b/src/graphics/engine/particle.cpp @@ -953,7 +953,7 @@ void CParticle::FrameParticle(float rTime) m_particle[i].goal = m_particle[i].pos; if (object != nullptr && object->Implements(ObjectInterfaceType::Damageable)) { - dynamic_cast(object)->DamageObject(DamageType::Phazer, 0.002f, m_particle[i].objFather); + dynamic_cast(*object).DamageObject(DamageType::Phazer, 0.002f, m_particle[i].objFather); } m_particle[i].zoom = 1.0f-(m_particle[i].time-m_particle[i].duration); @@ -1156,7 +1156,7 @@ void CParticle::FrameParticle(float rTime) { if (object->Implements(ObjectInterfaceType::Damageable)) { - dynamic_cast(object)->DamageObject(DamageType::Fire, 0.001f, m_particle[i].objFather); + dynamic_cast(*object).DamageObject(DamageType::Fire, 0.001f, m_particle[i].objFather); } m_exploGunCounter++; @@ -1222,7 +1222,7 @@ void CParticle::FrameParticle(float rTime) m_particle[i].goal = m_particle[i].pos; if (object != nullptr) { - if (object->GetType() == OBJECT_MOBILErs && dynamic_cast(object)->GetActiveShieldRadius() > 0.0f) // protected by shield? + if (object->GetType() == OBJECT_MOBILErs && dynamic_cast(*object).GetActiveShieldRadius() > 0.0f) // protected by shield? { CreateParticle(m_particle[i].pos, Math::Vector(0.0f, 0.0f, 0.0f), Math::Point(6.0f, 6.0f), PARTIGUNDEL, 2.0f); if (m_lastTimeGunDel > 0.2f) @@ -1240,7 +1240,7 @@ void CParticle::FrameParticle(float rTime) if (object->Implements(ObjectInterfaceType::Damageable)) { - dynamic_cast(object)->DamageObject(DamageType::Organic, 0.1f, m_particle[i].objFather); // starts explosion + dynamic_cast(*object).DamageObject(DamageType::Organic, 0.1f, m_particle[i].objFather); // starts explosion } } } @@ -1270,7 +1270,7 @@ void CParticle::FrameParticle(float rTime) m_particle[i].goal = m_particle[i].pos; if (object != nullptr) { - if (object->GetType() == OBJECT_MOBILErs && dynamic_cast(object)->GetActiveShieldRadius() > 0.0f) + if (object->GetType() == OBJECT_MOBILErs && dynamic_cast(*object).GetActiveShieldRadius() > 0.0f) { CreateParticle(m_particle[i].pos, Math::Vector(0.0f, 0.0f, 0.0f), Math::Point(6.0f, 6.0f), PARTIGUNDEL, 2.0f); if (m_lastTimeGunDel > 0.2f) @@ -1285,7 +1285,7 @@ void CParticle::FrameParticle(float rTime) { if (object->Implements(ObjectInterfaceType::Damageable)) { - dynamic_cast(object)->DamageObject(DamageType::Fire, std::numeric_limits::infinity(), m_particle[i].objFather); // starts explosion + dynamic_cast(*object).DamageObject(DamageType::Fire, std::numeric_limits::infinity(), m_particle[i].objFather); // starts explosion } } } @@ -1344,7 +1344,7 @@ void CParticle::FrameParticle(float rTime) { if (object->Implements(ObjectInterfaceType::Damageable)) { - dynamic_cast(object)->DamageObject(DamageType::Organic, 0.001f, m_particle[i].objFather); + dynamic_cast(*object).DamageObject(DamageType::Organic, 0.001f, m_particle[i].objFather); } m_exploGunCounter ++; @@ -2422,7 +2422,7 @@ void CParticle::FrameParticle(float rTime) if (object != nullptr) { assert(object->Implements(ObjectInterfaceType::Damageable)); - dynamic_cast(object)->DamageObject(DamageType::Tower, std::numeric_limits::infinity(), m_particle[i].objFather); + dynamic_cast(*object).DamageObject(DamageType::Tower, std::numeric_limits::infinity(), m_particle[i].objFather); } } diff --git a/src/graphics/engine/pyro.cpp b/src/graphics/engine/pyro.cpp index d295985a..33c144b8 100644 --- a/src/graphics/engine/pyro.cpp +++ b/src/graphics/engine/pyro.cpp @@ -129,7 +129,7 @@ bool CPyro::Create(PyroType type, CObject* obj, float force) CObject* power = nullptr; if (obj->Implements(ObjectInterfaceType::Powered)) - power = dynamic_cast(obj)->GetPower(); + power = dynamic_cast(*obj).GetPower(); if (power == nullptr) { @@ -260,7 +260,7 @@ bool CPyro::Create(PyroType type, CObject* obj, float force) m_sound->Play(SOUND_DEADw, m_pos); } assert(m_object->Implements(ObjectInterfaceType::Controllable)); - if ( type == PT_SHOTH && dynamic_cast(m_object)->GetSelect() ) + if ( type == PT_SHOTH && dynamic_cast(*m_object).GetSelect() ) { m_sound->Play(SOUND_AIE, m_pos); m_sound->Play(SOUND_AIE, m_engine->GetEyePt()); @@ -278,10 +278,10 @@ bool CPyro::Create(PyroType type, CObject* obj, float force) if ( m_type == PT_DEADG ) { assert(m_object->Implements(ObjectInterfaceType::Destroyable)); - dynamic_cast(m_object)->SetDying(DeathType::Dead); + dynamic_cast(*m_object).SetDying(DeathType::Dead); assert(obj->Implements(ObjectInterfaceType::Movable)); - dynamic_cast(obj)->GetMotion()->SetAction(MHS_DEADg, 1.0f); + dynamic_cast(*obj).GetMotion()->SetAction(MHS_DEADg, 1.0f); m_camera->StartCentering(m_object, Math::PI*0.5f, 99.9f, 0.0f, 1.5f); m_camera->StartOver(CAM_OVER_EFFECT_FADEOUT_WHITE, m_pos, 1.0f); @@ -291,10 +291,10 @@ bool CPyro::Create(PyroType type, CObject* obj, float force) if ( m_type == PT_DEADW ) { assert(m_object->Implements(ObjectInterfaceType::Destroyable)); - dynamic_cast(m_object)->SetDying(DeathType::Dead); + dynamic_cast(*m_object).SetDying(DeathType::Dead); assert(obj->Implements(ObjectInterfaceType::Movable)); - dynamic_cast(obj)->GetMotion()->SetAction(MHS_DEADw, 1.0f); + dynamic_cast(*obj).GetMotion()->SetAction(MHS_DEADw, 1.0f); m_camera->StartCentering(m_object, Math::PI*0.5f, 99.9f, 0.0f, 3.0f); m_camera->StartOver(CAM_OVER_EFFECT_FADEOUT_BLACK, m_pos, 1.0f); @@ -312,7 +312,7 @@ bool CPyro::Create(PyroType type, CObject* obj, float force) if ( m_type == PT_SHOTH ) { assert(m_object->Implements(ObjectInterfaceType::Controllable)); - if ( m_camera->GetBlood() && dynamic_cast(m_object)->GetSelect() ) + if ( m_camera->GetBlood() && dynamic_cast(*m_object).GetSelect() ) { m_camera->StartOver(CAM_OVER_EFFECT_BLOOD, m_pos, force); } @@ -1413,7 +1413,7 @@ void CPyro::DeleteObject(bool primary, bool secondary) if (m_object->Implements(ObjectInterfaceType::Transportable)) { // TODO: this should be handled in the object's destructor - CObject* transporter = dynamic_cast(m_object)->GetTransporter(); + CObject* transporter = dynamic_cast(*m_object).GetTransporter(); if (transporter != nullptr) { if (transporter->Implements(ObjectInterfaceType::Powered)) @@ -1582,12 +1582,12 @@ void CPyro::ExploStart() m_object->Simplify(); m_object->SetLock(true); // ruin not usable yet assert(m_object->Implements(ObjectInterfaceType::Destroyable)); - dynamic_cast(m_object)->SetDying(DeathType::Exploding); // being destroyed + dynamic_cast(*m_object).SetDying(DeathType::Exploding); // being destroyed m_object->FlatParent(); - if ( m_object->Implements(ObjectInterfaceType::Controllable) && dynamic_cast(m_object)->GetSelect() ) + if ( m_object->Implements(ObjectInterfaceType::Controllable) && dynamic_cast(*m_object).GetSelect() ) { - dynamic_cast(m_object)->SetSelect(false); // deselects the object + dynamic_cast(*m_object).SetSelect(false); // deselects the object m_camera->SetType(CAM_TYPE_EXPLO); m_main->DeselectAll(); } @@ -1611,7 +1611,7 @@ void CPyro::ExploStart() // TODO: temporary hack (hopefully) assert(m_object->Implements(ObjectInterfaceType::Old)); - Math::Vector pos = dynamic_cast(m_object)->GetPartPosition(i); + Math::Vector pos = dynamic_cast(*m_object).GetPartPosition(i); Math::Vector speed; float weight; @@ -1658,9 +1658,9 @@ void CPyro::BurnStart() m_object->Simplify(); m_object->SetLock(true); // ruin not usable yet - if ( m_object->Implements(ObjectInterfaceType::Controllable) && dynamic_cast(m_object)->GetSelect() ) + if ( m_object->Implements(ObjectInterfaceType::Controllable) && dynamic_cast(*m_object).GetSelect() ) { - dynamic_cast(m_object)->SetSelect(false); // deselects the object + dynamic_cast(*m_object).SetSelect(false); // deselects the object m_camera->SetType(CAM_TYPE_EXPLO); m_main->DeselectAll(); } @@ -2198,7 +2198,7 @@ void CPyro::BurnProgress() if (m_object->Implements(ObjectInterfaceType::Powered)) { - CObject* sub = dynamic_cast(m_object)->GetPower(); + CObject* sub = dynamic_cast(*m_object).GetPower(); if (sub != nullptr) // is there a battery? sub->SetScaleY(1.0f - m_progress); // complete flattening } @@ -2292,7 +2292,7 @@ CObject* CPyro::FallSearchBeeExplo() if (obj->GetType() == OBJECT_MOBILErs) { - float shieldRadius = dynamic_cast(obj)->GetActiveShieldRadius(); + float shieldRadius = dynamic_cast(*obj).GetActiveShieldRadius(); if ( shieldRadius > 0.0f ) { float distance = Math::Distance(oPos, bulletCrashSphere.sphere.pos); @@ -2360,12 +2360,12 @@ void CPyro::FallProgress(float rTime) { assert(m_object->Implements(ObjectInterfaceType::Destroyable)); // TODO: implement "killer"? - dynamic_cast(m_object)->DestroyObject(DestructionType::Explosion); + dynamic_cast(*m_object).DestroyObject(DestructionType::Explosion); } } else { - if (obj->GetType() == OBJECT_MOBILErs && dynamic_cast(obj)->GetActiveShieldRadius() > 0.0f) // protected by shield? + if (obj->GetType() == OBJECT_MOBILErs && dynamic_cast(*obj).GetActiveShieldRadius() > 0.0f) // protected by shield? { m_particle->CreateParticle(pos, Math::Vector(0.0f, 0.0f, 0.0f), Math::Point(6.0f, 6.0f), PARTIGUNDEL, 2.0f, 0.0f, 0.0f); @@ -2376,7 +2376,7 @@ void CPyro::FallProgress(float rTime) else { assert(obj->Implements(ObjectInterfaceType::Damageable)); - if (dynamic_cast(obj)->DamageObject(DamageType::FallingObject)) + if (dynamic_cast(*obj).DamageObject(DamageType::FallingObject)) { DeleteObject(true, true); // removes the ball } @@ -2384,7 +2384,7 @@ void CPyro::FallProgress(float rTime) { assert(m_object->Implements(ObjectInterfaceType::Destroyable)); // TODO: implement "killer"? - dynamic_cast(m_object)->DestroyObject(DestructionType::Explosion); + dynamic_cast(*m_object).DestroyObject(DestructionType::Explosion); } } } diff --git a/src/level/mainmovie.cpp b/src/level/mainmovie.cpp index 045a64ed..6a34510d 100644 --- a/src/level/mainmovie.cpp +++ b/src/level/mainmovie.cpp @@ -90,7 +90,7 @@ bool CMainMovie::Start(MainMovieType type, float time) } assert(pObj->Implements(ObjectInterfaceType::Movable)); - dynamic_cast(pObj)->GetMotion()->SetAction(MHS_SATCOM, 0.5f); // reads the SatCom + dynamic_cast(*pObj).GetMotion()->SetAction(MHS_SATCOM, 0.5f); // reads the SatCom m_camera->GetCamera(m_initialEye, m_initialLookat); m_camera->SetType(Gfx::CAM_TYPE_SCRIPT); @@ -110,7 +110,7 @@ bool CMainMovie::Start(MainMovieType type, float time) if ( pObj != nullptr ) { assert(pObj->Implements(ObjectInterfaceType::Movable)); - dynamic_cast(pObj)->GetMotion()->SetAction(-1); // finishes reading SatCom + dynamic_cast(*pObj).GetMotion()->SetAction(-1); // finishes reading SatCom } m_camera->SetType(Gfx::CAM_TYPE_BACK); @@ -132,7 +132,7 @@ bool CMainMovie::Stop() if ( pObj != nullptr ) { assert(pObj->Implements(ObjectInterfaceType::Movable)); - dynamic_cast(pObj)->GetMotion()->SetAction(-1); // finishes reading SatCom + dynamic_cast(*pObj).GetMotion()->SetAction(-1); // finishes reading SatCom } } diff --git a/src/level/robotmain.cpp b/src/level/robotmain.cpp index 619b7c7f..9ad03c8e 100644 --- a/src/level/robotmain.cpp +++ b/src/level/robotmain.cpp @@ -1361,7 +1361,7 @@ void CRobotMain::ExecuteCmd(const std::string& cmd) { CObject* object = GetSelect(); if (object != nullptr && object->Implements(ObjectInterfaceType::Shielded)) - dynamic_cast(object)->SetMagnifyDamage(dynamic_cast(object)->GetMagnifyDamage()*0.1f); + dynamic_cast(*object).SetMagnifyDamage(dynamic_cast(*object).GetMagnifyDamage()*0.1f); return; } @@ -1369,7 +1369,7 @@ void CRobotMain::ExecuteCmd(const std::string& cmd) { CObject* object = GetSelect(); if (object != nullptr && object->Implements(ObjectInterfaceType::JetFlying)) - dynamic_cast(object)->SetRange(dynamic_cast(object)->GetRange()*10.0f); + dynamic_cast(*object).SetRange(dynamic_cast(*object).GetRange()*10.0f); return; } @@ -1394,16 +1394,16 @@ void CRobotMain::ExecuteCmd(const std::string& cmd) { if (object->Implements(ObjectInterfaceType::Powered)) { - CObject* power = dynamic_cast(object)->GetPower(); + CObject* power = dynamic_cast(*object).GetPower(); if (power != nullptr && power->Implements(ObjectInterfaceType::PowerContainer)) - dynamic_cast(power)->SetEnergyLevel(1.0f); + dynamic_cast(*power).SetEnergyLevel(1.0f); } if (object->Implements(ObjectInterfaceType::Shielded)) - dynamic_cast(object)->SetShield(1.0f); + dynamic_cast(*object).SetShield(1.0f); if (object->Implements(ObjectInterfaceType::JetFlying)) - dynamic_cast(object)->SetReactorRange(1.0f); + dynamic_cast(*object).SetReactorRange(1.0f); } return; } @@ -1416,9 +1416,9 @@ void CRobotMain::ExecuteCmd(const std::string& cmd) { if (object->Implements(ObjectInterfaceType::Powered)) { - CObject* power = dynamic_cast(object)->GetPower(); + CObject* power = dynamic_cast(*object).GetPower(); if (power != nullptr && power->Implements(ObjectInterfaceType::PowerContainer)) - dynamic_cast(power)->SetEnergyLevel(1.0f); + dynamic_cast(*power).SetEnergyLevel(1.0f); } } return; @@ -1428,7 +1428,7 @@ void CRobotMain::ExecuteCmd(const std::string& cmd) { CObject* object = GetSelect(); if (object != nullptr && object->Implements(ObjectInterfaceType::Shielded)) - dynamic_cast(object)->SetShield(1.0f); + dynamic_cast(*object).SetShield(1.0f); return; } @@ -1438,7 +1438,7 @@ void CRobotMain::ExecuteCmd(const std::string& cmd) if (object != nullptr) { if (object->Implements(ObjectInterfaceType::JetFlying)) - dynamic_cast(object)->SetReactorRange(1.0f); + dynamic_cast(*object).SetReactorRange(1.0f); } return; } @@ -1538,7 +1538,7 @@ void CRobotMain::StartDisplayInfo(int index, bool movie) if (!m_editLock && movie && !m_movie->IsExist() && human) { assert(obj->Implements(ObjectInterfaceType::Movable)); - if (dynamic_cast(obj)->GetMotion()->GetAction() == -1) + if (dynamic_cast(*obj).GetMotion()->GetAction() == -1) { m_movieInfoIndex = index; m_movie->Start(MM_SATCOMopen, 2.5f); @@ -1852,7 +1852,7 @@ CObject* CRobotMain::DeselectAll() void CRobotMain::SelectOneObject(CObject* obj, bool displayError) { assert(obj->Implements(ObjectInterfaceType::Controllable)); - dynamic_cast(obj)->SetSelect(true, displayError); + dynamic_cast(*obj).SetSelect(true, displayError); m_camera->SetControllingObject(obj); ObjectType type = obj->GetType(); @@ -1891,7 +1891,7 @@ void CRobotMain::SelectOneObject(CObject* obj, bool displayError) type == OBJECT_MOBILEdr || type == OBJECT_APOLLO2 ) { - m_camera->SetType(dynamic_cast(obj)->GetCameraType()); + m_camera->SetType(dynamic_cast(*obj).GetCameraType()); } else { @@ -1907,7 +1907,7 @@ bool CRobotMain::SelectObject(CObject* obj, bool displayError) if (m_movieLock || m_editLock) return false; if (m_movie->IsExist()) return false; if (obj != nullptr && - (!obj->Implements(ObjectInterfaceType::Controllable) || !(dynamic_cast(obj)->GetSelectable() || m_cheatSelectInsect))) return false; + (!obj->Implements(ObjectInterfaceType::Controllable) || !(dynamic_cast(*obj).GetSelectable() || m_cheatSelectInsect))) return false; if (m_missionType == MISSION_CODE_BATTLE && m_codeBattleStarted && m_codeBattleSpectator) { @@ -1983,7 +1983,7 @@ CObject* CRobotMain::GetSelect() for (CObject* obj : m_objMan->GetAllObjects()) { if (!obj->Implements(ObjectInterfaceType::Controllable)) continue; - if (dynamic_cast(obj)->GetSelect()) + if (dynamic_cast(*obj).GetSelect()) return obj; } return nullptr; @@ -2001,7 +2001,7 @@ CObject* CRobotMain::DetectObject(Math::Point pos) CObject* transporter = nullptr; if (obj->Implements(ObjectInterfaceType::Transportable)) - transporter = dynamic_cast(obj)->GetTransporter(); + transporter = dynamic_cast(*obj).GetTransporter(); if (transporter != nullptr && !transporter->GetDetectable()) continue; if (obj->GetProxyActivate()) continue; @@ -2009,14 +2009,14 @@ CObject* CRobotMain::DetectObject(Math::Point pos) CObject* target = obj; if (obj->Implements(ObjectInterfaceType::PowerContainer) && obj->Implements(ObjectInterfaceType::Transportable)) { - target = dynamic_cast(obj)->GetTransporter(); // battery connected + target = dynamic_cast(*obj).GetTransporter(); // battery connected if (target == nullptr) { target = obj; // standalone battery } else { - if (!target->Implements(ObjectInterfaceType::Powered) || dynamic_cast(target)->GetPower() != obj) + if (!target->Implements(ObjectInterfaceType::Powered) || dynamic_cast(*target).GetPower() != obj) { // transported, but not in the power slot target = obj; @@ -2046,7 +2046,7 @@ bool CRobotMain::DestroySelectedObject() m_engine->GetPyroManager()->Create(Gfx::PT_FRAGT, obj); - dynamic_cast(obj)->SetSelect(false); // deselects the object + dynamic_cast(*obj).SetSelect(false); // deselects the object m_camera->SetType(Gfx::CAM_TYPE_EXPLO); DeselectAll(); RemoveFromSelectionHistory(obj); @@ -2069,7 +2069,7 @@ void CRobotMain::HiliteClear() for (CObject* obj : m_objMan->GetAllObjects()) { if (!obj->Implements(ObjectInterfaceType::Controllable)) continue; - dynamic_cast(obj)->SetHighlight(false); + dynamic_cast(*obj).SetHighlight(false); } m_map->SetHighlight(nullptr); m_short->SetHighlight(nullptr); @@ -2129,12 +2129,12 @@ void CRobotMain::HiliteObject(Math::Point pos) } } - if (obj->Implements(ObjectInterfaceType::Controllable) && (dynamic_cast(obj)->GetSelectable() || m_cheatSelectInsect)) + if (obj->Implements(ObjectInterfaceType::Controllable) && (dynamic_cast(*obj).GetSelectable() || m_cheatSelectInsect)) { - if (dynamic_cast(obj)->GetSelectable()) + if (dynamic_cast(*obj).GetSelectable()) { // Don't highlight objects that would not be selectable without selectinsect - dynamic_cast(obj)->SetHighlight(true); + dynamic_cast(*obj).SetHighlight(true); } m_map->SetHighlight(obj); m_short->SetHighlight(obj); @@ -2391,7 +2391,7 @@ bool CRobotMain::EventFrame(const Event &event) if (obj->GetType() == OBJECT_TOTO) toto = obj; else if (obj->Implements(ObjectInterfaceType::Interactive)) - dynamic_cast(obj)->EventProcess(event); + dynamic_cast(*obj).EventProcess(event); if ( obj->GetProxyActivate() ) // active if it is near? { @@ -2414,7 +2414,7 @@ bool CRobotMain::EventFrame(const Event &event) continue; if (obj->Implements(ObjectInterfaceType::Interactive)) - dynamic_cast(obj)->EventProcess(event); + dynamic_cast(*obj).EventProcess(event); } m_engine->GetPyroManager()->EventProcess(event); @@ -2438,7 +2438,7 @@ bool CRobotMain::EventFrame(const Event &event) // Advances toto following the camera, because its position depends on the camera. if (toto != nullptr) - dynamic_cast(toto)->EventProcess(event); + dynamic_cast(*toto).EventProcess(event); // NOTE: m_movieLock is set only after the first update of CAutoBase finishes @@ -2671,7 +2671,7 @@ bool CRobotMain::EventObject(const Event &event) { if (obj->Implements(ObjectInterfaceType::Interactive)) { - dynamic_cast(obj)->EventProcess(event); + dynamic_cast(*obj).EventProcess(event); } } @@ -2712,7 +2712,7 @@ void CRobotMain::ScenePerso() obj->SetDrawFront(true); // draws the interface assert(obj->Implements(ObjectInterfaceType::Movable)); - CMotionHuman* mh = static_cast(dynamic_cast(obj)->GetMotion()); + CMotionHuman* mh = static_cast(dynamic_cast(*obj).GetMotion()); mh->StartDisplayPerso(); } } @@ -3382,7 +3382,7 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) assert(m_controller->Implements(ObjectInterfaceType::ProgramStorage)); assert(m_controller->Implements(ObjectInterfaceType::Old)); - dynamic_cast(m_controller)->SetCheckToken(false); + dynamic_cast(*m_controller).SetCheckToken(false); if (line->GetParam("script")->IsDefined()) { @@ -3390,7 +3390,7 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) Program* program = programStorage->AddProgram(); programStorage->ReadProgram(program, line->GetParam("script")->AsPath("ai")); program->readOnly = true; - dynamic_cast(m_controller)->RunProgram(program); + dynamic_cast(*m_controller).RunProgram(program); } continue; } @@ -3415,7 +3415,7 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) if (m_fixScene && obj->GetType() == OBJECT_HUMAN) { assert(obj->Implements(ObjectInterfaceType::Movable)); - CMotion* motion = dynamic_cast(obj)->GetMotion(); + CMotion* motion = dynamic_cast(*obj).GetMotion(); if (m_phase == PHASE_WIN ) motion->SetAction(MHS_WIN, 0.4f); if (m_phase == PHASE_LOST) motion->SetAction(MHS_LOST, 0.5f); } @@ -3430,7 +3430,7 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) { CProgramStorageObject* programStorage = dynamic_cast(obj); - if (obj->Implements(ObjectInterfaceType::Controllable) && dynamic_cast(obj)->GetSelectable() && obj->GetType() != OBJECT_HUMAN) + if (obj->Implements(ObjectInterfaceType::Controllable) && dynamic_cast(*obj).GetSelectable() && obj->GetType() != OBJECT_HUMAN) { programStorage->SetProgramStorageIndex(rankObj); } @@ -3813,7 +3813,7 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) assert(obj->Implements(ObjectInterfaceType::Controllable)); SelectObject(obj); m_camera->SetControllingObject(obj); - m_camera->SetType(dynamic_cast(obj)->GetCameraType()); + m_camera->SetType(dynamic_cast(*obj).GetCameraType()); } } @@ -4410,7 +4410,7 @@ void CRobotMain::StartShowLimit() CObject* obj = GetSelect(); if (obj == nullptr) return; if (!obj->Implements(ObjectInterfaceType::Ranged)) return; - float range = dynamic_cast(obj)->GetShowLimitRadius(); + float range = dynamic_cast(*obj).GetShowLimitRadius(); if (range == 0.0f) return; SetShowLimit(0, Gfx::PARTILIMIT1, obj, obj->GetPosition(), range); } @@ -4580,8 +4580,8 @@ bool CRobotMain::IOIsBusy() { if (! obj->Implements(ObjectInterfaceType::TaskExecutor)) continue; - if (obj->Implements(ObjectInterfaceType::Programmable) && dynamic_cast(obj)->IsProgram()) continue; // TODO: I'm not sure if this is correct but this is how it worked earlier - if (dynamic_cast(obj)->IsForegroundTask()) return true; + if (obj->Implements(ObjectInterfaceType::Programmable) && dynamic_cast(*obj).IsProgram()) continue; // TODO: I'm not sure if this is correct but this is how it worked earlier + if (dynamic_cast(*obj).IsForegroundTask()) return true; } return false; } @@ -4632,7 +4632,7 @@ void CRobotMain::IOWriteObject(CLevelParserLine* line, CObject* obj, const std:: if (obj->Implements(ObjectInterfaceType::Programmable)) { - int run = dynamic_cast(obj)->GetProgramIndex(dynamic_cast(obj)->GetCurrentProgram()); + int run = dynamic_cast(*obj).GetProgramIndex(dynamic_cast(*obj).GetCurrentProgram()); if (run != -1) { line->AddParam("run", MakeUnique(run+1)); @@ -4707,11 +4707,11 @@ bool CRobotMain::IOWriteScene(std::string filename, std::string filecbot, std::s { if (obj->GetType() == OBJECT_TOTO) continue; if (IsObjectBeingTransported(obj)) continue; - if (obj->Implements(ObjectInterfaceType::Destroyable) && dynamic_cast(obj)->IsDying()) continue; + if (obj->Implements(ObjectInterfaceType::Destroyable) && dynamic_cast(*obj).IsDying()) continue; if (obj->Implements(ObjectInterfaceType::Carrier)) { - CObject* cargo = dynamic_cast(obj)->GetCargo(); + CObject* cargo = dynamic_cast(*obj).GetCargo(); if (cargo != nullptr) // object transported? { line = MakeUnique("CreateFret"); @@ -4722,7 +4722,7 @@ bool CRobotMain::IOWriteScene(std::string filename, std::string filecbot, std::s if (obj->Implements(ObjectInterfaceType::Powered)) { - CObject* power = dynamic_cast(obj)->GetPower(); + CObject* power = dynamic_cast(*obj).GetPower(); if (power != nullptr) // battery transported? { line = MakeUnique("CreatePower"); @@ -4761,7 +4761,7 @@ bool CRobotMain::IOWriteScene(std::string filename, std::string filecbot, std::s { if (obj->GetType() == OBJECT_TOTO) continue; if (IsObjectBeingTransported(obj)) continue; - if (obj->Implements(ObjectInterfaceType::Destroyable) && dynamic_cast(obj)->IsDying()) continue; + if (obj->Implements(ObjectInterfaceType::Destroyable) && dynamic_cast(*obj).IsDying()) continue; if (!SaveFileStack(obj, ostr)) { @@ -4912,7 +4912,7 @@ CObject* CRobotMain::IOReadScene(std::string filename, std::string filecbot) { assert(obj->Implements(ObjectInterfaceType::Carrier)); // TODO: exception? assert(obj->Implements(ObjectInterfaceType::Old)); - dynamic_cast(obj)->SetCargo(cargo); + dynamic_cast(*obj).SetCargo(cargo); auto task = MakeUnique(dynamic_cast(obj)); task->Start(TMO_AUTO, TMA_GRAB); // holds the object! } @@ -4920,9 +4920,9 @@ CObject* CRobotMain::IOReadScene(std::string filename, std::string filecbot) if (power != nullptr) { assert(obj->Implements(ObjectInterfaceType::Powered)); - dynamic_cast(obj)->SetPower(power); + dynamic_cast(*obj).SetPower(power); assert(power->Implements(ObjectInterfaceType::Transportable)); - dynamic_cast(power)->SetTransporter(obj); + dynamic_cast(*power).SetTransporter(obj); } cargo = nullptr; power = nullptr; @@ -4954,7 +4954,7 @@ CObject* CRobotMain::IOReadScene(std::string filename, std::string filecbot) { if (obj->GetType() == OBJECT_TOTO) continue; if (IsObjectBeingTransported(obj)) continue; - if (obj->Implements(ObjectInterfaceType::Destroyable) && dynamic_cast(obj)->IsDying()) continue; + if (obj->Implements(ObjectInterfaceType::Destroyable) && dynamic_cast(*obj).IsDying()) continue; if (!ReadFileStack(obj, istr)) { @@ -5311,7 +5311,7 @@ Error CRobotMain::CheckEndMission(bool frame) if (m_base != nullptr && !m_endTakeImmediat) { assert(m_base->Implements(ObjectInterfaceType::Controllable)); - if(dynamic_cast(m_base)->GetSelectable()) + if(dynamic_cast(*m_base).GetSelectable()) return ERR_MISSION_NOTERM; } } diff --git a/src/level/scene_conditions.cpp b/src/level/scene_conditions.cpp index 41a8a8f0..36e2bdd9 100644 --- a/src/level/scene_conditions.cpp +++ b/src/level/scene_conditions.cpp @@ -82,7 +82,7 @@ bool CObjectCondition::CheckForObject(CObject* obj) } else if (obj->Implements(ObjectInterfaceType::Powered)) { - CObject* powerObj = dynamic_cast(obj)->GetPower(); + CObject* powerObj = dynamic_cast(*obj).GetPower(); if(powerObj != nullptr && powerObj->Implements(ObjectInterfaceType::PowerContainer)) { power = dynamic_cast(powerObj); @@ -98,7 +98,7 @@ bool CObjectCondition::CheckForObject(CObject* obj) Math::Vector oPos; if (IsObjectBeingTransported(obj)) - oPos = dynamic_cast(obj)->GetTransporter()->GetPosition(); + oPos = dynamic_cast(*obj).GetTransporter()->GetPosition(); else oPos = obj->GetPosition(); oPos.y = 0.0f; diff --git a/src/object/auto/autobase.cpp b/src/object/auto/autobase.cpp index d5522c56..7b908095 100644 --- a/src/object/auto/autobase.cpp +++ b/src/object/auto/autobase.cpp @@ -169,7 +169,7 @@ begin: else { assert(pObj->Implements(ObjectInterfaceType::Controllable)); - m_camera->SetType(dynamic_cast(pObj)->GetCameraType()); + m_camera->SetType(dynamic_cast(*pObj).GetCameraType()); } m_main->StartMusic(); @@ -594,7 +594,7 @@ begin: else { assert(pObj->Implements(ObjectInterfaceType::Controllable)); - m_camera->SetType(dynamic_cast(pObj)->GetCameraType()); + m_camera->SetType(dynamic_cast(*pObj).GetCameraType()); } m_sound->Play(SOUND_BOUM, m_object->GetPosition()); m_soundChannel = -1; @@ -1124,7 +1124,7 @@ bool CAutoBase::Abort() else { assert(pObj->Implements(ObjectInterfaceType::Controllable)); - m_camera->SetType(dynamic_cast(pObj)->GetCameraType()); + m_camera->SetType(dynamic_cast(*pObj).GetCameraType()); } m_engine->SetFogStart(m_fogStart); @@ -1248,7 +1248,7 @@ void CAutoBase::FreezeCargo(bool freeze) m_cargoObjects.insert(obj); if ( obj->Implements(ObjectInterfaceType::Movable) ) { - CPhysics* physics = dynamic_cast(obj)->GetPhysics(); + CPhysics* physics = dynamic_cast(*obj).GetPhysics(); physics->SetFreeze(freeze); } } diff --git a/src/object/auto/autodestroyer.cpp b/src/object/auto/autodestroyer.cpp index f30acebf..717a1f2b 100644 --- a/src/object/auto/autodestroyer.cpp +++ b/src/object/auto/autodestroyer.cpp @@ -176,7 +176,7 @@ bool CAutoDestroyer::EventProcess(const Event &event) if ( scrap != nullptr ) { assert(scrap->Implements(ObjectInterfaceType::Destroyable)); - dynamic_cast(scrap)->DestroyObject(DestructionType::Explosion); + dynamic_cast(*scrap).DestroyObject(DestructionType::Explosion); } m_bExplo = true; } diff --git a/src/object/auto/autoegg.cpp b/src/object/auto/autoegg.cpp index a4e7d493..6c0026d8 100644 --- a/src/object/auto/autoegg.cpp +++ b/src/object/auto/autoegg.cpp @@ -74,7 +74,7 @@ void CAutoEgg::DeleteObject(bool all) alien->SetLock(false); if (alien->Implements(ObjectInterfaceType::Programmable)) { - dynamic_cast(alien)->SetActivity(true); // the insect is active + dynamic_cast(*alien).SetActivity(true); // the insect is active } } else @@ -123,7 +123,7 @@ void CAutoEgg::Init() if (alien->Implements(ObjectInterfaceType::Programmable)) { - dynamic_cast(alien)->SetActivity(false); + dynamic_cast(*alien).SetActivity(false); } } @@ -204,7 +204,7 @@ bool CAutoEgg::EventProcess(const Event &event) if ( alien == nullptr ) return true; if (alien->Implements(ObjectInterfaceType::Programmable)) { - dynamic_cast(alien)->SetActivity(false); + dynamic_cast(*alien).SetActivity(false); } m_progress += event.rTime*m_speed; @@ -265,7 +265,7 @@ Error CAutoEgg::IsEnded() alien->SetLock(false); if(alien->Implements(ObjectInterfaceType::Programmable)) { - dynamic_cast(alien)->SetActivity(true); // the insect is active + dynamic_cast(*alien).SetActivity(true); // the insect is active } } diff --git a/src/object/auto/autofactory.cpp b/src/object/auto/autofactory.cpp index 9ba1f3e1..a6061a32 100644 --- a/src/object/auto/autofactory.cpp +++ b/src/object/auto/autofactory.cpp @@ -397,7 +397,7 @@ bool CAutoFactory::EventProcess(const Event &event) if ( vehicle != nullptr ) { assert(vehicle->Implements(ObjectInterfaceType::Movable)); - physics = dynamic_cast(vehicle)->GetPhysics(); + physics = dynamic_cast(*vehicle).GetPhysics(); physics->SetFreeze(false); // can move vehicle->SetLock(false); // vehicle useable @@ -408,7 +408,7 @@ bool CAutoFactory::EventProcess(const Event &event) { if (vehicle->Implements(ObjectInterfaceType::Programmable) && vehicle->Implements(ObjectInterfaceType::ProgramStorage)) { - Program* program = dynamic_cast(vehicle)->AddProgram(); + Program* program = dynamic_cast(*vehicle).AddProgram(); if (boost::regex_match(m_program, boost::regex("[A-Za-z0-9_]+"))) // Public function name? { @@ -424,7 +424,7 @@ bool CAutoFactory::EventProcess(const Event &event) program->script->SendScript(m_program.c_str()); } - dynamic_cast(vehicle)->RunProgram(program); + dynamic_cast(*vehicle).RunProgram(program); } } } @@ -670,7 +670,7 @@ bool CAutoFactory::CreateVehicle() vehicle->SetLock(true); // not usable assert(vehicle->Implements(ObjectInterfaceType::Movable)); - CPhysics* physics = dynamic_cast(vehicle)->GetPhysics(); + CPhysics* physics = dynamic_cast(*vehicle).GetPhysics(); physics->SetFreeze(true); // it doesn't move if (vehicle->Implements(ObjectInterfaceType::ProgramStorage)) diff --git a/src/object/auto/autonuclearplant.cpp b/src/object/auto/autonuclearplant.cpp index 14fd6fc3..2c138c61 100644 --- a/src/object/auto/autonuclearplant.cpp +++ b/src/object/auto/autonuclearplant.cpp @@ -400,7 +400,7 @@ void CAutoNuclearPlant::CreatePower() float powerLevel = 1.0f; CObject* power = CObjectManager::GetInstancePointer()->CreateObject(pos, angle, OBJECT_ATOMIC, powerLevel); - dynamic_cast(power)->SetTransporter(m_object); + dynamic_cast(*power).SetTransporter(m_object); power->SetPosition(Math::Vector(22.0f, 3.0f, 0.0f)); m_object->SetPower(power); } diff --git a/src/object/auto/autopowercaptor.cpp b/src/object/auto/autopowercaptor.cpp index d10a6c88..614c5da4 100644 --- a/src/object/auto/autopowercaptor.cpp +++ b/src/object/auto/autopowercaptor.cpp @@ -269,7 +269,7 @@ void CAutoPowerCaptor::ChargeObject(float rTime) if (obj->Implements(ObjectInterfaceType::Powered)) { - CObject* power = dynamic_cast(obj)->GetPower(); + CObject* power = dynamic_cast(*obj).GetPower(); if ( power != nullptr && power->Implements(ObjectInterfaceType::PowerContainer) ) { CPowerContainerObject* powerContainer = dynamic_cast(power); @@ -285,7 +285,7 @@ void CAutoPowerCaptor::ChargeObject(float rTime) if (obj->Implements(ObjectInterfaceType::Carrier)) { - CObject* power = dynamic_cast(obj)->GetCargo(); + CObject* power = dynamic_cast(*obj).GetCargo(); if ( power != nullptr && power->Implements(ObjectInterfaceType::PowerContainer) ) { CPowerContainerObject* powerContainer = dynamic_cast(power); diff --git a/src/object/auto/autopowerplant.cpp b/src/object/auto/autopowerplant.cpp index 50447573..d0006e2d 100644 --- a/src/object/auto/autopowerplant.cpp +++ b/src/object/auto/autopowerplant.cpp @@ -331,7 +331,7 @@ bool CAutoPowerPlant::EventProcess(const Event &event) cargo->SetScale(1.0f); cargo->SetLock(false); // usable battery - dynamic_cast(cargo)->SetTransporter(m_object); + dynamic_cast(*cargo).SetTransporter(m_object); cargo->SetPosition(Math::Vector(0.0f, 3.0f, 0.0f)); m_object->SetPower(cargo); diff --git a/src/object/auto/autopowerstation.cpp b/src/object/auto/autopowerstation.cpp index 0693c7c7..96bed578 100644 --- a/src/object/auto/autopowerstation.cpp +++ b/src/object/auto/autopowerstation.cpp @@ -138,7 +138,7 @@ bool CAutoPowerStation::EventProcess(const Event &event) { if (vehicle->Implements(ObjectInterfaceType::Powered)) { - CObject* power = dynamic_cast(vehicle)->GetPower(); + CObject* power = dynamic_cast(*vehicle).GetPower(); if ( power != nullptr && power->Implements(ObjectInterfaceType::PowerContainer) ) { CPowerContainerObject* powerContainer = dynamic_cast(power); @@ -158,7 +158,7 @@ bool CAutoPowerStation::EventProcess(const Event &event) if (vehicle->Implements(ObjectInterfaceType::Carrier)) { - CObject* power = dynamic_cast(vehicle)->GetCargo(); + CObject* power = dynamic_cast(*vehicle).GetCargo(); if ( power != nullptr && power->Implements(ObjectInterfaceType::PowerContainer) ) { CPowerContainerObject* powerContainer = dynamic_cast(power); diff --git a/src/object/auto/autorepair.cpp b/src/object/auto/autorepair.cpp index f860f732..39b41d42 100644 --- a/src/object/auto/autorepair.cpp +++ b/src/object/auto/autorepair.cpp @@ -148,7 +148,7 @@ bool CAutoRepair::EventProcess(const Event &event) assert(vehicle->Implements(ObjectInterfaceType::Shielded)); if ( m_progress < 1.0f || - (vehicle != nullptr && dynamic_cast(vehicle)->GetShield() < 1.0f) ) + (vehicle != nullptr && dynamic_cast(*vehicle).GetShield() < 1.0f) ) { if ( vehicle != nullptr ) { @@ -243,9 +243,9 @@ CObject* CAutoRepair::SearchVehicle() { if (obj == m_object) continue; if ( !obj->Implements(ObjectInterfaceType::Shielded) ) continue; - if ( !dynamic_cast(obj)->IsRepairable() ) continue; + if ( !dynamic_cast(*obj).IsRepairable() ) continue; - if ( obj->Implements(ObjectInterfaceType::Movable) && !dynamic_cast(obj)->GetPhysics()->GetLand() ) continue; // in flight? + if ( obj->Implements(ObjectInterfaceType::Movable) && !dynamic_cast(*obj).GetPhysics()->GetLand() ) continue; // in flight? Math::Vector oPos = obj->GetPosition(); float dist = Math::Distance(oPos, sPos); diff --git a/src/object/auto/autotower.cpp b/src/object/auto/autotower.cpp index 65d83277..b509e7e9 100644 --- a/src/object/auto/autotower.cpp +++ b/src/object/auto/autotower.cpp @@ -289,7 +289,7 @@ CObject* CAutoTower::SearchTarget(Math::Vector &impact) { if ( obj->Implements(ObjectInterfaceType::Movable) ) { - CPhysics* physics = dynamic_cast(obj)->GetPhysics(); + CPhysics* physics = dynamic_cast(*obj).GetPhysics(); float speed = fabs(physics->GetLinMotionX(MO_REASPEED)); if ( speed > 20.0f ) continue; // moving too fast? } @@ -302,8 +302,7 @@ CObject* CAutoTower::SearchTarget(Math::Vector &impact) if ( distance > TOWER_SCOPE ) continue; // too far if ( distance < min ) { - min = distance; - best = obj; + min = distance; best = obj; } } if ( best == nullptr ) return nullptr; @@ -327,7 +326,7 @@ Error CAutoTower::GetError() return ERR_TOWER_POWER; // no battery } - if ( dynamic_cast(m_object->GetPower())->GetEnergy() < ENERGY_FIRE ) + if ( dynamic_cast(*m_object->GetPower()).GetEnergy() < ENERGY_FIRE ) { return ERR_TOWER_ENERGY; // not enough energy } diff --git a/src/object/implementation/program_storage_impl.cpp b/src/object/implementation/program_storage_impl.cpp index ced1a4c7..d5a914ff 100644 --- a/src/object/implementation/program_storage_impl.cpp +++ b/src/object/implementation/program_storage_impl.cpp @@ -270,7 +270,7 @@ void CProgramStorageObjectImpl::LoadAllProgramsForLevel(CLevelParserLine* levelS if (m_object->Implements(ObjectInterfaceType::Programmable) && i == run) { - dynamic_cast(m_object)->RunProgram(program); + dynamic_cast(*m_object).RunProgram(program); } } else @@ -327,7 +327,7 @@ void CProgramStorageObjectImpl::SaveAllProgramsForSavedScene(CLevelParserLine* l } if (m_programStorageIndex < 0) return; - if (!m_object->Implements(ObjectInterfaceType::Controllable) || !dynamic_cast(m_object)->GetSelectable() || m_object->GetType() == OBJECT_HUMAN) return; + if (!m_object->Implements(ObjectInterfaceType::Controllable) || !dynamic_cast(*m_object).GetSelectable() || m_object->GetType() == OBJECT_HUMAN) return; GetLogger()->Debug("Saving saved scene programs to '%s/prog%.3d___.txt'\n", levelSource.c_str(), m_programStorageIndex); for (unsigned int i = 0; i < m_program.size(); i++) @@ -379,7 +379,7 @@ void CProgramStorageObjectImpl::LoadAllProgramsForSavedScene(CLevelParserLine* l if (m_object->Implements(ObjectInterfaceType::Programmable) && i == run) { - dynamic_cast(m_object)->RunProgram(program); + dynamic_cast(*m_object).RunProgram(program); } } } @@ -403,7 +403,7 @@ void CProgramStorageObjectImpl::LoadAllProgramsForSavedScene(CLevelParserLine* l if (m_object->Implements(ObjectInterfaceType::Programmable) && i == run) { - dynamic_cast(m_object)->RunProgram(program); + dynamic_cast(*m_object).RunProgram(program); } } } diff --git a/src/object/implementation/programmable_impl.cpp b/src/object/implementation/programmable_impl.cpp index f21bf4b7..8748f040 100644 --- a/src/object/implementation/programmable_impl.cpp +++ b/src/object/implementation/programmable_impl.cpp @@ -68,7 +68,7 @@ bool CProgrammableObjectImpl::EventProcess(const Event &event) { if (event.type == EVENT_FRAME) { - if ( m_object->Implements(ObjectInterfaceType::Destroyable) && dynamic_cast(m_object)->IsDying() && IsProgram() ) + if ( m_object->Implements(ObjectInterfaceType::Destroyable) && dynamic_cast(*m_object).IsDying() && IsProgram() ) { StopProgram(); } @@ -113,7 +113,7 @@ void CProgrammableObjectImpl::RunProgram(Program* program) { m_currentProgram = program; // start new program m_object->UpdateInterface(); - if (m_object->Implements(ObjectInterfaceType::Controllable) && dynamic_cast(m_object)->GetTrainer()) + if (m_object->Implements(ObjectInterfaceType::Controllable) && dynamic_cast(*m_object).GetTrainer()) CRobotMain::GetInstancePointer()->StartMissionTimer(); } } @@ -155,7 +155,7 @@ bool CProgrammableObjectImpl::ReadStack(std::istream &istr) { if (m_object->Implements(ObjectInterfaceType::ProgramStorage)) { - int count = static_cast(dynamic_cast(m_object)->GetProgramCount()); + int count = static_cast(dynamic_cast(*m_object).GetProgramCount()); if (!(op < count)) { GetLogger()->Info("Object program count: %i\n", count); @@ -163,7 +163,7 @@ bool CProgrammableObjectImpl::ReadStack(std::istream &istr) return false; } - m_currentProgram = dynamic_cast(m_object)->GetProgram(op); + m_currentProgram = dynamic_cast(*m_object).GetProgram(op); if (!m_currentProgram->script->ReadStack(istr)) { GetLogger()->Error("Restore state failed at program index: %i\n", op); @@ -203,7 +203,7 @@ bool CProgrammableObjectImpl::WriteStack(std::ostream &ostr) op = -1; if (m_object->Implements(ObjectInterfaceType::ProgramStorage)) { - op = dynamic_cast(m_object)->GetProgramIndex(m_currentProgram); + op = dynamic_cast(*m_object).GetProgramIndex(m_currentProgram); } if (!CBot::WriteShort(ostr, op)) return false; @@ -266,7 +266,7 @@ void CProgrammableObjectImpl::TraceRecordFrame() assert(m_object->Implements(ObjectInterfaceType::TraceDrawing)); CTraceDrawingObject* traceDrawing = dynamic_cast(m_object); - CPhysics* physics = dynamic_cast(m_object)->GetPhysics(); + CPhysics* physics = dynamic_cast(*m_object).GetPhysics(); speed = physics->GetLinMotionX(MO_REASPEED); if ( speed > 0.0f ) oper = TO_ADVANCE; @@ -353,7 +353,7 @@ void CProgrammableObjectImpl::TraceRecordStop() buffer << "}\n"; assert(m_object->Implements(ObjectInterfaceType::ProgramStorage)); - Program* prog = dynamic_cast(m_object)->AddProgram(); + Program* prog = dynamic_cast(*m_object).AddProgram(); prog->script->SendScript(buffer.str().c_str()); } diff --git a/src/object/motion/motionant.cpp b/src/object/motion/motionant.cpp index 889e6d96..2b4cf2c7 100644 --- a/src/object/motion/motionant.cpp +++ b/src/object/motion/motionant.cpp @@ -429,7 +429,7 @@ bool CMotionAnt::EventFrame(const Event &event) assert(m_object->Implements(ObjectInterfaceType::Destroyable)); if ( dynamic_cast(m_object)->GetDying() == DeathType::Burning ) // burning? { - if ( dynamic_cast(m_object)->GetFixed() ) + if ( dynamic_cast(*m_object).GetFixed() ) { m_actionType = MAS_BURN; } @@ -724,7 +724,7 @@ bool CMotionAnt::EventFrame(const Event &event) if ( m_progress >= 1.0f ) { SetAction(-1); - dynamic_cast(m_object)->SetFixed(false); // moving again + dynamic_cast(*m_object).SetFixed(false); // moving again } } else diff --git a/src/object/motion/motionspider.cpp b/src/object/motion/motionspider.cpp index ec8af342..c65807f1 100644 --- a/src/object/motion/motionspider.cpp +++ b/src/object/motion/motionspider.cpp @@ -364,7 +364,7 @@ bool CMotionSpider::EventFrame(const Event &event) assert(m_object->Implements(ObjectInterfaceType::Destroyable)); if (dynamic_cast(m_object)->GetDying() == DeathType::Burning ) // burning? { - if ( dynamic_cast(m_object)->GetFixed() ) + if ( dynamic_cast(*m_object).GetFixed() ) { m_actionType = MSS_BURN; } @@ -648,7 +648,7 @@ bool CMotionSpider::EventFrame(const Event &event) if ( m_progress >= 1.0f ) { SetAction(-1); - dynamic_cast(m_object)->SetFixed(false); // moving again + dynamic_cast(*m_object).SetFixed(false); // moving again } } else diff --git a/src/object/motion/motionvehicle.cpp b/src/object/motion/motionvehicle.cpp index 4f2a09f1..b9719c34 100644 --- a/src/object/motion/motionvehicle.cpp +++ b/src/object/motion/motionvehicle.cpp @@ -1075,7 +1075,7 @@ void CMotionVehicle::Create(Math::Vector pos, float angle, ObjectType type, powerCell->SetPosition(powerCellPos); powerCell->SetRotation(Math::Vector(0.0f, powerCellAngle, 0.0f)); - dynamic_cast(powerCell)->SetTransporter(m_object); + dynamic_cast(*powerCell).SetTransporter(m_object); assert(m_object->Implements(ObjectInterfaceType::Powered)); m_object->SetPower(powerCell); } diff --git a/src/object/object_manager.cpp b/src/object/object_manager.cpp index bab1f3ac..7650bedb 100644 --- a/src/object/object_manager.cpp +++ b/src/object/object_manager.cpp @@ -217,7 +217,7 @@ void CObjectManager::DestroyTeam(int team, DestructionType destructionType) { if (object->Implements(ObjectInterfaceType::Destroyable)) { - dynamic_cast(object)->DestroyObject(destructionType); + dynamic_cast(*object).DestroyObject(destructionType); } else { @@ -336,7 +336,7 @@ std::vector CObjectManager::RadarAll(CObject* pThis, Math::Vector this { if ( pObj->Implements(ObjectInterfaceType::Movable) ) { - CPhysics* physics = dynamic_cast(pObj)->GetPhysics(); + CPhysics* physics = dynamic_cast(*pObj).GetPhysics(); if ( physics != nullptr ) { if ( !physics->GetLand() ) continue; @@ -346,7 +346,7 @@ std::vector CObjectManager::RadarAll(CObject* pThis, Math::Vector this if ( filter_flying == FILTER_ONLYFLYING ) { if ( !pObj->Implements(ObjectInterfaceType::Movable) ) continue; - CPhysics* physics = dynamic_cast(pObj)->GetPhysics(); + CPhysics* physics = dynamic_cast(*pObj).GetPhysics(); if ( physics == nullptr ) continue; if ( physics->GetLand() ) continue; } diff --git a/src/object/old_object.cpp b/src/object/old_object.cpp index eaffaa10..002b8e28 100644 --- a/src/object/old_object.cpp +++ b/src/object/old_object.cpp @@ -285,8 +285,8 @@ void COldObject::DeleteObject(bool bAll) { if (m_power->Implements(ObjectInterfaceType::Old)) { - dynamic_cast(m_power)->SetTransporter(nullptr); - dynamic_cast(m_power)->DeleteObject(bAll); + dynamic_cast(*m_power).SetTransporter(nullptr); + dynamic_cast(*m_power).DeleteObject(bAll); } m_power = nullptr; } @@ -294,8 +294,8 @@ void COldObject::DeleteObject(bool bAll) { if (m_cargo->Implements(ObjectInterfaceType::Old)) { - dynamic_cast(m_cargo)->SetTransporter(nullptr); - dynamic_cast(m_cargo)->DeleteObject(bAll); + dynamic_cast(*m_cargo).SetTransporter(nullptr); + dynamic_cast(*m_cargo).DeleteObject(bAll); } m_cargo = nullptr; } diff --git a/src/object/task/taskfire.cpp b/src/object/task/taskfire.cpp index 72247447..87730880 100644 --- a/src/object/task/taskfire.cpp +++ b/src/object/task/taskfire.cpp @@ -317,7 +317,7 @@ Error CTaskFire::Start(float delay) CObject* power = dynamic_cast(m_object)->GetPower(); if (power == nullptr || !power->Implements(ObjectInterfaceType::PowerContainer)) return ERR_FIRE_ENERGY; - energy = dynamic_cast(power)->GetEnergy(); + energy = dynamic_cast(*power).GetEnergy(); if ( m_bOrganic ) fire = m_delay*ENERGY_FIREi; else if ( m_bRay ) fire = m_delay*ENERGY_FIREr; else fire = m_delay*ENERGY_FIRE; diff --git a/src/object/task/taskfireant.cpp b/src/object/task/taskfireant.cpp index a1ee384f..99bc7d0b 100644 --- a/src/object/task/taskfireant.cpp +++ b/src/object/task/taskfireant.cpp @@ -60,7 +60,7 @@ bool CTaskFireAnt::EventProcess(const Event &event) if ( event.type != EVENT_FRAME ) return true; if ( m_bError ) return false; - if ( dynamic_cast(m_object)->GetFixed() ) // insect on its back? + if ( dynamic_cast(*m_object).GetFixed() ) // insect on its back? { m_bError = true; return false; @@ -100,7 +100,7 @@ Error CTaskFireAnt::Start(Math::Vector impact) if ( type != OBJECT_ANT ) return ERR_WRONG_BOT; // Insect on its back? - if ( dynamic_cast(m_object)->GetFixed() ) return ERR_WRONG_BOT; + if ( dynamic_cast(*m_object).GetFixed() ) return ERR_WRONG_BOT; m_physics->SetMotorSpeed(Math::Vector(0.0f, 0.0f, 0.0f)); @@ -130,7 +130,7 @@ Error CTaskFireAnt::IsEnded() if ( m_engine->GetPause() ) return ERR_CONTINUE; if ( m_bError ) return ERR_STOP; - if ( dynamic_cast(m_object)->GetFixed() ) return ERR_STOP; // insect on its back? + if ( dynamic_cast(*m_object).GetFixed() ) return ERR_STOP; // insect on its back? if ( m_phase == TFA_TURN ) // rotation ? { diff --git a/src/object/task/taskgoto.cpp b/src/object/task/taskgoto.cpp index 1224b391..d2e64667 100644 --- a/src/object/task/taskgoto.cpp +++ b/src/object/task/taskgoto.cpp @@ -1202,7 +1202,7 @@ bool CTaskGoto::AdjustTarget(CObject* pObj, Math::Vector &pos, float &distance) type == OBJECT_MOBILEdr ) { assert(pObj->Implements(ObjectInterfaceType::Powered)); - pos = dynamic_cast(pObj)->GetPowerPosition(); + pos = dynamic_cast(*pObj).GetPowerPosition(); pos.x -= TAKE_DIST+TAKE_DIST_OTHER+distance; mat = pObj->GetWorldMatrix(0); pos = Transform(*mat, pos); diff --git a/src/object/task/taskmanip.cpp b/src/object/task/taskmanip.cpp index ff55962f..aa62ef9e 100644 --- a/src/object/task/taskmanip.cpp +++ b/src/object/task/taskmanip.cpp @@ -304,8 +304,8 @@ Error CTaskManip::Start(TaskManipOrder order, TaskManipArm arm) assert(other->Implements(ObjectInterfaceType::Transportable)); m_object->SetCargo(other); // takes the ball - dynamic_cast(other)->SetTransporter(m_object); - dynamic_cast(other)->SetTransporterPart(0); // taken with the base + dynamic_cast(*other).SetTransporter(m_object); + dynamic_cast(*other).SetTransporterPart(0); // taken with the base other->SetPosition(Math::Vector(0.0f, -3.0f, 0.0f)); } else @@ -314,7 +314,7 @@ Error CTaskManip::Start(TaskManipOrder order, TaskManipArm arm) assert(other->Implements(ObjectInterfaceType::Transportable)); m_object->SetCargo(nullptr); // lick the ball - dynamic_cast(other)->SetTransporter(nullptr); + dynamic_cast(*other).SetTransporter(nullptr); pos = m_object->GetPosition(); pos.y -= 3.0f; other->SetPosition(pos); @@ -903,7 +903,7 @@ CObject* CTaskManip::SearchOtherObject(bool bAdvance, Math::Vector &pos, ObjectType type = pObj->GetType(); if ( !pObj->Implements(ObjectInterfaceType::Powered) ) continue; - CObject* power = dynamic_cast(pObj)->GetPower(); + CObject* power = dynamic_cast(*pObj).GetPower(); if (power != nullptr) { if (power->GetLock()) continue; @@ -911,7 +911,7 @@ CObject* CTaskManip::SearchOtherObject(bool bAdvance, Math::Vector &pos, } mat = pObj->GetWorldMatrix(0); - Math::Vector oPos = Transform(*mat, dynamic_cast(pObj)->GetPowerPosition()); + Math::Vector oPos = Transform(*mat, dynamic_cast(*pObj).GetPowerPosition()); oAngle = pObj->GetRotationY(); if ( type == OBJECT_TOWER || @@ -946,7 +946,7 @@ CObject* CTaskManip::SearchOtherObject(bool bAdvance, Math::Vector &pos, angle = Math::RotateAngle(oPos.x-iPos.x, iPos.z-oPos.z); // CW ! if ( Math::TestAngle(angle, iAngle-aLimit, iAngle+aLimit) ) { - Math::Vector powerPos = dynamic_cast(pObj)->GetPowerPosition(); + Math::Vector powerPos = dynamic_cast(*pObj).GetPowerPosition(); height = powerPos.y; pos = oPos; return pObj; @@ -974,8 +974,8 @@ bool CTaskManip::TransporterTakeObject() if ( m_object->GetType() == OBJECT_HUMAN || m_object->GetType() == OBJECT_TECH ) { - dynamic_cast(cargo)->SetTransporter(m_object); - dynamic_cast(cargo)->SetTransporterPart(4); // takes with the hand + dynamic_cast(*cargo).SetTransporter(m_object); + dynamic_cast(*cargo).SetTransporterPart(4); // takes with the hand cargo->SetPosition(Math::Vector(1.7f, -0.5f, 1.1f)); cargo->SetRotationY(0.1f); @@ -984,8 +984,8 @@ bool CTaskManip::TransporterTakeObject() } else if ( m_bSubm ) { - dynamic_cast(cargo)->SetTransporter(m_object); - dynamic_cast(cargo)->SetTransporterPart(2); // takes with the right claw + dynamic_cast(*cargo).SetTransporter(m_object); + dynamic_cast(*cargo).SetTransporterPart(2); // takes with the right claw Math::Vector pos = Math::Vector(1.1f, -1.0f, 1.0f); // relative cargo->SetPosition(pos); @@ -995,8 +995,8 @@ bool CTaskManip::TransporterTakeObject() } else { - dynamic_cast(cargo)->SetTransporter(m_object); - dynamic_cast(cargo)->SetTransporterPart(3); // takes with the hand + dynamic_cast(*cargo).SetTransporter(m_object); + dynamic_cast(*cargo).SetTransporterPart(3); // takes with the hand Math::Vector pos = Math::Vector(4.7f, 0.0f, 0.0f); // relative to the hand (lem4) cargo->SetPosition(pos); @@ -1020,8 +1020,8 @@ bool CTaskManip::TransporterTakeObject() if ( m_bSubm ) { - dynamic_cast(cargo)->SetTransporter(m_object); - dynamic_cast(cargo)->SetTransporterPart(2); // takes with the right claw + dynamic_cast(*cargo).SetTransporter(m_object); + dynamic_cast(*cargo).SetTransporterPart(2); // takes with the right claw pos = Math::Vector(1.1f, -1.0f, 1.0f); // relative cargo->SetPosition(pos); @@ -1031,8 +1031,8 @@ bool CTaskManip::TransporterTakeObject() } else { - dynamic_cast(cargo)->SetTransporter(m_object); - dynamic_cast(cargo)->SetTransporterPart(3); // takes with the hand + dynamic_cast(*cargo).SetTransporter(m_object); + dynamic_cast(*cargo).SetTransporterPart(3); // takes with the hand pos = Math::Vector(4.7f, 0.0f, 0.0f); // relative to the hand (lem4) cargo->SetPosition(pos); @@ -1054,8 +1054,8 @@ bool CTaskManip::TransporterTakeObject() m_cargoType = cargo->GetType(); - dynamic_cast(cargo)->SetTransporter(m_object); - dynamic_cast(cargo)->SetTransporterPart(3); // takes with the hand + dynamic_cast(*cargo).SetTransporter(m_object); + dynamic_cast(*cargo).SetTransporterPart(3); // takes with the hand pos = Math::Vector(4.7f, 0.0f, 0.0f); // relative to the hand (lem4) cargo->SetPosition(pos); @@ -1080,7 +1080,7 @@ bool CTaskManip::TransporterTakeObject() cargo->SetRotationX(0.0f); cargo->SetRotationZ(Math::PI/2.0f); cargo->SetRotationY(0.0f); - dynamic_cast(cargo)->SetTransporterPart(3); // takes with the hand + dynamic_cast(*cargo).SetTransporterPart(3); // takes with the hand m_object->SetPower(nullptr); m_object->SetCargo(cargo); // takes @@ -1094,15 +1094,15 @@ bool CTaskManip::TransporterTakeObject() if (other == nullptr) return false; assert(other->Implements(ObjectInterfaceType::Powered)); - CObject* cargo = dynamic_cast(other)->GetPower(); + CObject* cargo = dynamic_cast(*other).GetPower(); if (cargo == nullptr) return false; // the other does not have a battery? assert(cargo->Implements(ObjectInterfaceType::Transportable)); m_cargoType = cargo->GetType(); - dynamic_cast(other)->SetPower(nullptr); - dynamic_cast(cargo)->SetTransporter(m_object); - dynamic_cast(cargo)->SetTransporterPart(3); // takes with the hand + dynamic_cast(*other).SetPower(nullptr); + dynamic_cast(*cargo).SetTransporter(m_object); + dynamic_cast(*cargo).SetTransporterPart(3); // takes with the hand pos = Math::Vector(4.7f, 0.0f, 0.0f); // relative to the hand (lem4) cargo->SetPosition(pos); @@ -1137,7 +1137,7 @@ bool CTaskManip::TransporterDeposeObject() cargo->SetRotationZ(0.0f); cargo->FloorAdjust(); // plate well on the ground - dynamic_cast(cargo)->SetTransporter(nullptr); + dynamic_cast(*cargo).SetTransporter(nullptr); m_object->SetCargo(nullptr); // deposit } @@ -1157,7 +1157,7 @@ bool CTaskManip::TransporterDeposeObject() cargo->SetRotationX(0.0f); cargo->SetRotationZ(0.0f); - dynamic_cast(cargo)->SetTransporter(nullptr); + dynamic_cast(*cargo).SetTransporter(nullptr); m_object->SetCargo(nullptr); // deposit } @@ -1172,8 +1172,8 @@ bool CTaskManip::TransporterDeposeObject() if (m_object->GetPower() != nullptr) return false; - dynamic_cast(cargo)->SetTransporter(m_object); - dynamic_cast(cargo)->SetTransporterPart(0); // carried by the base + dynamic_cast(*cargo).SetTransporter(m_object); + dynamic_cast(*cargo).SetTransporterPart(0); // carried by the base cargo->SetPosition(m_object->GetPowerPosition()); cargo->SetRotationY(0.0f); @@ -1193,7 +1193,7 @@ bool CTaskManip::TransporterDeposeObject() if (other == nullptr) return false; assert(other->Implements(ObjectInterfaceType::Powered)); - CObject* cargo = dynamic_cast(other)->GetPower(); + CObject* cargo = dynamic_cast(*other).GetPower(); if (cargo != nullptr) return false; // the other already has a battery? cargo = m_object->GetCargo(); @@ -1202,14 +1202,14 @@ bool CTaskManip::TransporterDeposeObject() m_cargoType = cargo->GetType(); - dynamic_cast(other)->SetPower(cargo); - dynamic_cast(cargo)->SetTransporter(other); + dynamic_cast(*other).SetPower(cargo); + dynamic_cast(*cargo).SetTransporter(other); - cargo->SetPosition(dynamic_cast(other)->GetPowerPosition()); + cargo->SetPosition(dynamic_cast(*other).GetPowerPosition()); cargo->SetRotationY(0.0f); cargo->SetRotationX(0.0f); cargo->SetRotationZ(0.0f); - dynamic_cast(cargo)->SetTransporterPart(0); // carried by the base + dynamic_cast(*cargo).SetTransporterPart(0); // carried by the base m_object->SetCargo(nullptr); // deposit } diff --git a/src/object/task/taskrecover.cpp b/src/object/task/taskrecover.cpp index e039e7ae..f56503d5 100644 --- a/src/object/task/taskrecover.cpp +++ b/src/object/task/taskrecover.cpp @@ -194,7 +194,7 @@ Error CTaskRecover::Start() CObject* power = dynamic_cast(m_object)->GetPower(); if (power == nullptr || !power->Implements(ObjectInterfaceType::PowerContainer)) return ERR_RECOVER_ENERGY; - float energy = dynamic_cast(power)->GetEnergy(); + float energy = dynamic_cast(*power).GetEnergy(); if ( energy < ENERGY_RECOVER+0.05f ) return ERR_RECOVER_ENERGY; Math::Matrix* mat = m_object->GetWorldMatrix(0); diff --git a/src/object/task/taskshield.cpp b/src/object/task/taskshield.cpp index ad39a688..916a5158 100644 --- a/src/object/task/taskshield.cpp +++ b/src/object/task/taskshield.cpp @@ -309,7 +309,7 @@ Error CTaskShield::Start(TaskShieldMode mode, float delay) CObject* power = m_object->GetPower(); if (power == nullptr || !power->Implements(ObjectInterfaceType::PowerContainer)) return ERR_SHIELD_ENERGY; - float energy = dynamic_cast(power)->GetEnergy(); + float energy = dynamic_cast(*power).GetEnergy(); if ( energy == 0.0f ) return ERR_SHIELD_ENERGY; Math::Matrix* mat = m_object->GetWorldMatrix(0); diff --git a/src/object/task/taskspiderexplo.cpp b/src/object/task/taskspiderexplo.cpp index ed1b8ef7..2acab5fd 100644 --- a/src/object/task/taskspiderexplo.cpp +++ b/src/object/task/taskspiderexplo.cpp @@ -57,7 +57,7 @@ bool CTaskSpiderExplo::EventProcess(const Event &event) if ( event.type != EVENT_FRAME ) return true; // Momentarily stationary object (ant on the back)? - if ( dynamic_cast(m_object)->GetFixed() ) + if ( dynamic_cast(*m_object).GetFixed() ) { m_bError = true; return true; diff --git a/src/object/task/tasktake.cpp b/src/object/task/tasktake.cpp index c1c0de9e..6f7360bd 100644 --- a/src/object/task/tasktake.cpp +++ b/src/object/task/tasktake.cpp @@ -131,9 +131,9 @@ Error CTaskTake::Start() CObject* other = SearchFriendObject(oAngle, 1.5f, Math::PI*0.50f); if (other != nullptr) assert(other->Implements(ObjectInterfaceType::Powered)); - if (other != nullptr && dynamic_cast(other)->GetPower() != nullptr) + if (other != nullptr && dynamic_cast(*other).GetPower() != nullptr) { - CObject* power = dynamic_cast(other)->GetPower(); + CObject* power = dynamic_cast(*other).GetPower(); type = power->GetType(); if ( type == OBJECT_URANIUM ) return ERR_MANIP_RADIO; assert(power->Implements(ObjectInterfaceType::Transportable)); @@ -161,7 +161,7 @@ Error CTaskTake::Start() CObject* other = SearchFriendObject(oAngle, 1.5f, Math::PI*0.50f); if (other != nullptr) assert(other->Implements(ObjectInterfaceType::Powered)); - if (other != nullptr && dynamic_cast(other)->GetPower() == nullptr ) + if (other != nullptr && dynamic_cast(*other).GetPower() == nullptr ) { //? m_camera->StartCentering(m_object, Math::PI*0.3f, -Math::PI*0.1f, 0.0f, 0.8f); m_arm = TTA_FRIEND; @@ -390,7 +390,7 @@ CObject* CTaskTake::SearchFriendObject(float &angle, assert(pObj->Implements(ObjectInterfaceType::Powered)); - CObject* power = dynamic_cast(pObj)->GetPower(); + CObject* power = dynamic_cast(*pObj).GetPower(); if (power != nullptr) { if ( power->GetLock() ) continue; @@ -398,7 +398,7 @@ CObject* CTaskTake::SearchFriendObject(float &angle, } Math::Matrix* mat = pObj->GetWorldMatrix(0); - Math::Vector oPos = Math::Transform(*mat, dynamic_cast(pObj)->GetPowerPosition()); + Math::Vector oPos = Math::Transform(*mat, dynamic_cast(*pObj).GetPowerPosition()); float distance = fabs(Math::Distance(oPos, iPos) - (iRad+1.0f)); if ( distance <= dLimit ) @@ -406,7 +406,7 @@ CObject* CTaskTake::SearchFriendObject(float &angle, angle = Math::RotateAngle(oPos.x-iPos.x, iPos.z-oPos.z); // CW ! if ( Math::TestAngle(angle, iAngle-aLimit, iAngle+aLimit) ) { - Math::Vector powerPos = dynamic_cast(pObj)->GetPowerPosition(); + Math::Vector powerPos = dynamic_cast(*pObj).GetPowerPosition(); m_height = powerPos.y; return pObj; } @@ -430,8 +430,8 @@ bool CTaskTake::TransporterTakeObject() m_cargoType = cargo->GetType(); - dynamic_cast(cargo)->SetTransporter(m_object); - dynamic_cast(cargo)->SetTransporterPart(4); // takes with the hand + dynamic_cast(*cargo).SetTransporter(m_object); + dynamic_cast(*cargo).SetTransporterPart(4); // takes with the hand //? cargo->SetPosition(Math::Vector(2.2f, -1.0f, 1.1f)); cargo->SetPosition(Math::Vector(1.7f, -0.5f, 1.1f)); @@ -449,15 +449,15 @@ bool CTaskTake::TransporterTakeObject() if (other == nullptr) return false; assert(other->Implements(ObjectInterfaceType::Powered)); - CObject* cargo = dynamic_cast(other)->GetPower(); + CObject* cargo = dynamic_cast(*other).GetPower(); if (cargo == nullptr) return false; // the other does not have a battery? assert(cargo->Implements(ObjectInterfaceType::Transportable)); m_cargoType = cargo->GetType(); - dynamic_cast(other)->SetPower(nullptr); - dynamic_cast(cargo)->SetTransporter(m_object); - dynamic_cast(cargo)->SetTransporterPart(4); // takes with the hand + dynamic_cast(*other).SetPower(nullptr); + dynamic_cast(*cargo).SetTransporter(m_object); + dynamic_cast(*cargo).SetTransporterPart(4); // takes with the hand //? cargo->SetPosition(Math::Vector(2.2f, -1.0f, 1.1f)); cargo->SetPosition(Math::Vector(1.7f, -0.5f, 1.1f)); @@ -492,7 +492,7 @@ bool CTaskTake::TransporterDeposeObject() cargo->SetRotationZ(0.0f); cargo->FloorAdjust(); // plate well on the ground - dynamic_cast(cargo)->SetTransporter(nullptr); + dynamic_cast(*cargo).SetTransporter(nullptr); m_object->SetCargo(nullptr); // deposit } @@ -503,7 +503,7 @@ bool CTaskTake::TransporterDeposeObject() if (other == nullptr) return false; assert(other->Implements(ObjectInterfaceType::Powered)); - CObject* cargo = dynamic_cast(other)->GetPower(); + CObject* cargo = dynamic_cast(*other).GetPower(); if (cargo != nullptr) return false; // the other already has a battery? cargo = m_object->GetCargo(); @@ -511,14 +511,14 @@ bool CTaskTake::TransporterDeposeObject() assert(cargo->Implements(ObjectInterfaceType::Transportable)); m_cargoType = cargo->GetType(); - dynamic_cast(other)->SetPower(cargo); - dynamic_cast(cargo)->SetTransporter(other); + dynamic_cast(*other).SetPower(cargo); + dynamic_cast(*cargo).SetTransporter(other); - cargo->SetPosition(dynamic_cast(other)->GetPowerPosition()); + cargo->SetPosition(dynamic_cast(*other).GetPowerPosition()); cargo->SetRotationY(0.0f); cargo->SetRotationX(0.0f); cargo->SetRotationZ(0.0f); - dynamic_cast(cargo)->SetTransporterPart(0); // carried by the base + dynamic_cast(*cargo).SetTransporterPart(0); // carried by the base m_object->SetCargo(nullptr); // deposit } diff --git a/src/object/task/taskterraform.cpp b/src/object/task/taskterraform.cpp index c0267230..c0160bf8 100644 --- a/src/object/task/taskterraform.cpp +++ b/src/object/task/taskterraform.cpp @@ -215,7 +215,7 @@ Error CTaskTerraform::Start() power = m_object->GetPower(); if ( power == nullptr || !power->Implements(ObjectInterfaceType::PowerContainer) ) return ERR_TERRA_ENERGY; - energy = dynamic_cast(power)->GetEnergy(); + energy = dynamic_cast(*power).GetEnergy(); if ( energy < ENERGY_TERRA+0.05f ) return ERR_TERRA_ENERGY; speed = m_physics->GetMotorSpeed(); @@ -426,7 +426,7 @@ bool CTaskTerraform::Terraform() { if ( dist > 5.0f ) continue; m_engine->GetPyroManager()->Create(Gfx::PT_EXPLOT, pObj); - dynamic_cast(m_object)->DamageObject(DamageType::Explosive, 0.9f); + dynamic_cast(*m_object).DamageObject(DamageType::Explosive, 0.9f); } else if ( type == OBJECT_PLANT0 || type == OBJECT_PLANT1 || @@ -444,6 +444,7 @@ bool CTaskTerraform::Terraform() { if ( dist > 7.5f ) continue; m_engine->GetPyroManager()->Create(Gfx::PT_FRAGV, pObj); + } else // Other? { @@ -454,7 +455,7 @@ bool CTaskTerraform::Terraform() else { if ( !pObj->Implements(ObjectInterfaceType::Movable) ) continue; - motion = dynamic_cast(pObj)->GetMotion(); + motion = dynamic_cast(*pObj).GetMotion(); dist = Math::Distance(m_terraPos, pObj->GetPosition()); if ( dist > ACTION_RADIUS ) continue; @@ -462,13 +463,13 @@ bool CTaskTerraform::Terraform() if ( type == OBJECT_ANT || type == OBJECT_SPIDER ) { assert(pObj->Implements(ObjectInterfaceType::TaskExecutor)); - dynamic_cast(pObj)->StopForegroundTask(); + dynamic_cast(*pObj).StopForegroundTask(); int actionType = -1; if (type == OBJECT_ANT) actionType = MAS_BACK1; if (type == OBJECT_SPIDER) actionType = MSS_BACK1; motion->SetAction(actionType, 0.8f+Math::Rand()*0.3f); - dynamic_cast(pObj)->SetFixed(true); // not moving + dynamic_cast(*pObj).SetFixed(true); // not moving if ( dist > 5.0f ) continue; m_engine->GetPyroManager()->Create(Gfx::PT_EXPLOO, pObj); diff --git a/src/physics/physics.cpp b/src/physics/physics.cpp index 7dd79633..d3b69cd8 100644 --- a/src/physics/physics.cpp +++ b/src/physics/physics.cpp @@ -804,7 +804,7 @@ void CPhysics::MotorUpdate(float aTime, float rTime) if (m_object->Implements(ObjectInterfaceType::Powered)) { - power = dynamic_cast(dynamic_cast(m_object)->GetPower()); // searches for the object battery uses + power = dynamic_cast(dynamic_cast(*m_object).GetPower()); // searches for the object battery uses if ( GetObjectEnergy(m_object) == 0.0f ) // no battery or flat? { motorSpeed.x = 0.0f; @@ -822,7 +822,7 @@ void CPhysics::MotorUpdate(float aTime, float rTime) } } - if ( m_object->GetType() == OBJECT_HUMAN && dynamic_cast(m_object)->GetDying() == DeathType::Dead ) // dead man? + if ( m_object->GetType() == OBJECT_HUMAN && dynamic_cast(*m_object).GetDying() == DeathType::Dead ) // dead man? { motorSpeed.x = 0.0f; motorSpeed.z = 0.0f; @@ -852,7 +852,7 @@ void CPhysics::MotorUpdate(float aTime, float rTime) } if ( m_object->Implements(ObjectInterfaceType::JetFlying) && - dynamic_cast(m_object)->GetRange() > 0.0f ) // limited flight range? + dynamic_cast(*m_object).GetRange() > 0.0f ) // limited flight range? { CJetFlyingObject* jetFlying = dynamic_cast(m_object); if ( m_bLand || m_bSwim || m_bObstacle ) // on the ground or in the water? @@ -960,7 +960,7 @@ void CPhysics::MotorUpdate(float aTime, float rTime) bool reactorCool = true; if ( m_object->Implements(ObjectInterfaceType::JetFlying) ) { - reactorCool = dynamic_cast(m_object)->GetReactorRange() > 0.1f; + reactorCool = dynamic_cast(*m_object).GetReactorRange() > 0.1f; } if ( motorSpeed.y > 0.0f && reactorCool && pos.y < h ) { @@ -1463,7 +1463,7 @@ bool CPhysics::EventFrame(const Event &event) iAngle = angle = m_object->GetRotation(); // Accelerate is the descent, brake is the ascent. - if ( m_bFreeze || (m_object->Implements(ObjectInterfaceType::Destroyable) && dynamic_cast(m_object)->IsDying()) ) + if ( m_bFreeze || (m_object->Implements(ObjectInterfaceType::Destroyable) && dynamic_cast(*m_object).IsDying()) ) { m_linMotion.terrainSpeed.x = 0.0f; m_linMotion.terrainSpeed.z = 0.0f; @@ -1618,8 +1618,8 @@ void CPhysics::SoundMotor(float rTime) else if ( type == OBJECT_ANT ) { assert(m_object->Implements(ObjectInterfaceType::Destroyable)); - if ( dynamic_cast(m_object)->GetDying() == DeathType::Burning || - dynamic_cast(m_object)->GetFixed() ) + if ( dynamic_cast(*m_object).GetDying() == DeathType::Burning || + dynamic_cast(*m_object).GetFixed() ) { if ( m_lastSoundInsect <= 0.0f ) { @@ -1649,7 +1649,7 @@ void CPhysics::SoundMotor(float rTime) else m_lastSoundInsect = 1.5f+Math::Rand()*4.0f; } } - else if ( dynamic_cast(m_object)->GetDying() == DeathType::Burning ) + else if ( dynamic_cast(*m_object).GetDying() == DeathType::Burning ) { if ( m_lastSoundInsect <= 0.0f ) { @@ -1670,7 +1670,7 @@ void CPhysics::SoundMotor(float rTime) else m_lastSoundInsect = 1.5f+Math::Rand()*4.0f; } } - else if ( dynamic_cast(m_object)->GetDying() == DeathType::Burning ) + else if ( dynamic_cast(*m_object).GetDying() == DeathType::Burning ) { if ( m_lastSoundInsect <= 0.0f ) { @@ -1682,8 +1682,8 @@ void CPhysics::SoundMotor(float rTime) else if ( type == OBJECT_SPIDER ) { assert(m_object->Implements(ObjectInterfaceType::Destroyable)); - if ( dynamic_cast(m_object)->GetDying() == DeathType::Burning || - dynamic_cast(m_object)->GetFixed() ) + if ( dynamic_cast(*m_object).GetDying() == DeathType::Burning || + dynamic_cast(*m_object).GetFixed() ) { if ( m_lastSoundInsect <= 0.0f ) { @@ -2506,7 +2506,7 @@ int CPhysics::ObjectAdapt(const Math::Vector &pos, const Math::Vector &angle) int colType; ObjectType iType, oType; - if ( m_object->Implements(ObjectInterfaceType::Destroyable) && dynamic_cast(m_object)->IsDying() ) return 0; // is burning or exploding? + if ( m_object->Implements(ObjectInterfaceType::Destroyable) && dynamic_cast(*m_object).IsDying() ) return 0; // is burning or exploding? if ( !m_object->GetCollisions() ) return 0; // iiPos = sphere center is the old position. @@ -2525,7 +2525,7 @@ int CPhysics::ObjectAdapt(const Math::Vector &pos, const Math::Vector &angle) { if ( pObj == m_object ) continue; // yourself? if (IsObjectBeingTransported(pObj)) continue; - if ( pObj->Implements(ObjectInterfaceType::Destroyable) && dynamic_cast(pObj)->GetDying() == DeathType::Exploding ) continue; // is exploding? + if ( pObj->Implements(ObjectInterfaceType::Destroyable) && dynamic_cast(*pObj).GetDying() == DeathType::Exploding ) continue; // is exploding? oType = pObj->GetType(); if ( oType == OBJECT_TOTO ) continue; @@ -2627,7 +2627,7 @@ int CPhysics::ObjectAdapt(const Math::Vector &pos, const Math::Vector &angle) CPhysics* ph = nullptr; if (pObj->Implements(ObjectInterfaceType::Movable)) - ph = dynamic_cast(pObj)->GetPhysics(); + ph = dynamic_cast(*pObj).GetPhysics(); if ( ph != nullptr ) { oAngle = pObj->GetRotation(); @@ -2727,7 +2727,7 @@ bool CPhysics::ExploOther(ObjectType iType, if ( force > destructionForce && destructionForce >= 0.0f ) { // TODO: implement "killer"? - dynamic_cast(pObj)->DamageObject(damageType); + dynamic_cast(*pObj).DamageObject(damageType); } } @@ -2753,7 +2753,7 @@ bool CPhysics::ExploOther(ObjectType iType, { assert(pObj->Implements(ObjectInterfaceType::Damageable)); // TODO: implement "killer"? - dynamic_cast(pObj)->DamageObject(DamageType::Collision, force/400.0f); + dynamic_cast(*pObj).DamageObject(DamageType::Collision, force/400.0f); } if (oType == OBJECT_MOBILEwa || @@ -2790,7 +2790,7 @@ bool CPhysics::ExploOther(ObjectType iType, { assert(pObj->Implements(ObjectInterfaceType::Damageable)); // TODO: implement "killer"? - dynamic_cast(pObj)->DamageObject(DamageType::Collision, force/200.0f); + dynamic_cast(*pObj).DamageObject(DamageType::Collision, force/200.0f); } } @@ -2830,7 +2830,7 @@ int CPhysics::ExploHimself(ObjectType iType, ObjectType oType, float force) if ( force > destructionForce && destructionForce >= 0.0f ) { // TODO: implement "killer"? - dynamic_cast(m_object)->DamageObject(DamageType::Explosive); + dynamic_cast(*m_object).DamageObject(DamageType::Explosive); return 2; } @@ -2917,7 +2917,7 @@ int CPhysics::ExploHimself(ObjectType iType, ObjectType oType, float force) } // TODO: implement "killer"? - if ( dynamic_cast(m_object)->DamageObject(DamageType::Collision, force) ) return 2; + if ( dynamic_cast(*m_object).DamageObject(DamageType::Collision, force) ) return 2; } } @@ -2969,9 +2969,9 @@ void CPhysics::PowerParticle(float factor, bool bBreak) bCarryPower = false; if (m_object->Implements(ObjectInterfaceType::Carrier)) { - CObject* cargo = dynamic_cast(m_object)->GetCargo(); + CObject* cargo = dynamic_cast(*m_object).GetCargo(); if ( cargo != nullptr && cargo->Implements(ObjectInterfaceType::PowerContainer) && - dynamic_cast(cargo)->IsRechargeable() && + dynamic_cast(*cargo).IsRechargeable() && m_object->GetPartRotationZ(1) == ARM_STOCK_ANGLE1 ) { bCarryPower = true; // carries a battery @@ -3264,7 +3264,7 @@ void CPhysics::MotorParticle(float aTime, float rTime) } else // in flight? { - if ( !m_bMotor || (m_object->Implements(ObjectInterfaceType::JetFlying) && dynamic_cast(m_object)->GetReactorRange() == 0.0f) ) return; + if ( !m_bMotor || (m_object->Implements(ObjectInterfaceType::JetFlying) && dynamic_cast(*m_object).GetReactorRange() == 0.0f) ) return; if ( m_reactorTemperature < 1.0f ) // not too hot? { @@ -3394,7 +3394,7 @@ void CPhysics::MotorParticle(float aTime, float rTime) } else // in flight? { - if ( !m_bMotor || (m_object->Implements(ObjectInterfaceType::JetFlying) && dynamic_cast(m_object)->GetReactorRange() == 0.0f) ) return; + if ( !m_bMotor || (m_object->Implements(ObjectInterfaceType::JetFlying) && dynamic_cast(*m_object).GetReactorRange() == 0.0f) ) return; if ( aTime-m_lastMotorParticle < m_engine->ParticleAdapt(0.02f) ) return; m_lastMotorParticle = aTime; @@ -3455,7 +3455,7 @@ void CPhysics::MotorParticle(float aTime, float rTime) if ( (type == OBJECT_HUMAN || type == OBJECT_TECH) && m_bSwim ) { - if ( !m_object->Implements(ObjectInterfaceType::Destroyable) || dynamic_cast(m_object)->GetDying() != DeathType::Dead ) + if ( !m_object->Implements(ObjectInterfaceType::Destroyable) || dynamic_cast(*m_object).GetDying() != DeathType::Dead ) { h = Math::Mod(aTime, 5.0f); if ( h < 3.5f && ( h < 1.5f || h > 1.6f ) ) return; @@ -3778,7 +3778,7 @@ Error CPhysics::GetError() if (m_object->Implements(ObjectInterfaceType::ProgramStorage)) { - if ( dynamic_cast(m_object)->GetActiveVirus() ) + if ( dynamic_cast(*m_object).GetActiveVirus() ) { return ERR_VEH_VIRUS; } @@ -3786,14 +3786,14 @@ Error CPhysics::GetError() if (m_object->Implements(ObjectInterfaceType::Powered)) { - CObject* power = dynamic_cast(m_object)->GetPower(); // searches for the object battery used + CObject* power = dynamic_cast(*m_object).GetPower(); // searches for the object battery used if (power == nullptr || !power->Implements(ObjectInterfaceType::PowerContainer)) { return ERR_VEH_POWER; } else { - if ( dynamic_cast(power)->GetEnergy() == 0.0f ) return ERR_VEH_ENERGY; + if ( dynamic_cast(*power).GetEnergy() == 0.0f ) return ERR_VEH_ENERGY; } } diff --git a/src/script/scriptfunc.cpp b/src/script/scriptfunc.cpp index 7f09ed5e..724da61f 100644 --- a/src/script/scriptfunc.cpp +++ b/src/script/scriptfunc.cpp @@ -728,7 +728,7 @@ bool CScriptFunctions::rDelete(CBotVar* var, CBotVar* result, int& exception, vo } CObject* obj = CObjectManager::GetInstancePointer()->GetObjectById(rank); - if ( obj == nullptr || (obj->Implements(ObjectInterfaceType::Old) && dynamic_cast(obj)->IsDying()) ) + if ( obj == nullptr || (obj->Implements(ObjectInterfaceType::Old) && dynamic_cast(*obj).IsDying()) ) { return true; } @@ -739,7 +739,7 @@ bool CScriptFunctions::rDelete(CBotVar* var, CBotVar* result, int& exception, vo if ( exploType != DestructionType::NoEffect && obj->Implements(ObjectInterfaceType::Destroyable) ) { - dynamic_cast(obj)->DestroyObject(static_cast(exploType)); + dynamic_cast(*obj).DestroyObject(static_cast(exploType)); } else { @@ -1560,7 +1560,7 @@ bool CScriptFunctions::rProduce(CBotVar* var, CBotVar* result, int& exception, v CObjectManager::GetInstancePointer()->CreateObject(pos, angle, OBJECT_EGG); if (object->Implements(ObjectInterfaceType::Programmable)) { - dynamic_cast(object)->SetActivity(false); + dynamic_cast(*object).SetActivity(false); } } else @@ -1582,7 +1582,7 @@ bool CScriptFunctions::rProduce(CBotVar* var, CBotVar* result, int& exception, v if (type == OBJECT_MOBILEdr) { assert(object->Implements(ObjectInterfaceType::Old)); // TODO: temporary hack - dynamic_cast(object)->SetManual(true); + dynamic_cast(*object).SetManual(true); } script->m_main->CreateShortcuts(); } @@ -1597,7 +1597,7 @@ bool CScriptFunctions::rProduce(CBotVar* var, CBotVar* result, int& exception, v programStorage->ReadProgram(program, name2.c_str()); program->readOnly = true; program->filename = name; - dynamic_cast(object)->RunProgram(program); + dynamic_cast(*object).RunProgram(program); } } @@ -2203,7 +2203,7 @@ bool CScriptFunctions::rReceive(CBotVar* var, CBotVar* result, int& exception, v return true; } - CExchangePost* exchangePost = dynamic_cast(script->m_taskExecutor->GetForegroundTask())->FindExchangePost(power); + CExchangePost* exchangePost = dynamic_cast(*script->m_taskExecutor->GetForegroundTask()).FindExchangePost(power); script->m_returnValue = exchangePost->GetInfoValue(p); } if ( !WaitForForegroundTask(script, result, exception) ) return false; // not finished @@ -2488,7 +2488,7 @@ bool CScriptFunctions::rShield(CBotVar* var, CBotVar* result, int& exception, vo } else // up ? { - dynamic_cast(pThis)->SetShieldRadius(radius); + dynamic_cast(*pThis).SetShieldRadius(radius); err = script->m_taskExecutor->StartTaskShield(TSM_UP, 1000.0f); if ( err != ERR_OK ) { @@ -2506,7 +2506,7 @@ bool CScriptFunctions::rShield(CBotVar* var, CBotVar* result, int& exception, vo else // up? { //? result->SetValInt(1); // shows the error - dynamic_cast(pThis)->SetShieldRadius(radius); + dynamic_cast(*pThis).SetShieldRadius(radius); script->m_taskExecutor->StartTaskShield(TSM_UPDATE, 0.0f); } } @@ -2680,7 +2680,7 @@ bool CScriptFunctions::rMotor(CBotVar* var, CBotVar* result, int& exception, voi if ( turn < -1.0f ) turn = -1.0f; if ( turn > 1.0f ) turn = 1.0f; - if ( dynamic_cast(pThis) != nullptr && dynamic_cast(pThis)->GetFixed() ) // ant on the back? + if ( dynamic_cast(pThis) != nullptr && dynamic_cast(*pThis).GetFixed() ) // ant on the back? { speed = 0.0f; turn = 0.0f; @@ -2789,7 +2789,7 @@ bool CScriptFunctions::rCmdline(CBotVar* var, CBotVar* result, int& exception, v assert(pThis->Implements(ObjectInterfaceType::Programmable)); rank = var->GetValInt(); - value = dynamic_cast(pThis)->GetCmdLine(rank); + value = dynamic_cast(*pThis).GetCmdLine(rank); result->SetValFloat(value); return true; diff --git a/src/ui/controls/map.cpp b/src/ui/controls/map.cpp index ef485d82..9d9ebb48 100644 --- a/src/ui/controls/map.cpp +++ b/src/ui/controls/map.cpp @@ -1197,7 +1197,7 @@ void CMap::UpdateObject(CObject* pObj) type != OBJECT_WORM && type != OBJECT_MOBILEtg ) { - if (pObj->Implements(ObjectInterfaceType::Controllable) && !dynamic_cast(pObj)->GetSelectable()) return; + if (pObj->Implements(ObjectInterfaceType::Controllable) && !dynamic_cast(*pObj).GetSelectable()) return; } if ( pObj->GetProxyActivate() ) return; if (IsObjectBeingTransported(pObj)) return; @@ -1330,7 +1330,7 @@ void CMap::UpdateObject(CObject* pObj) color != MAPCOLOR_MOVE ) return; }*/ - if ( pObj->Implements(ObjectInterfaceType::Controllable) && dynamic_cast(pObj)->GetSelect() ) + if ( pObj->Implements(ObjectInterfaceType::Controllable) && dynamic_cast(*pObj).GetSelect() ) { m_map[MAPMAXOBJECT-1].type = type; m_map[MAPMAXOBJECT-1].object = pObj; diff --git a/src/ui/controls/target.cpp b/src/ui/controls/target.cpp index 2260aea1..24fa3c9a 100644 --- a/src/ui/controls/target.cpp +++ b/src/ui/controls/target.cpp @@ -143,13 +143,13 @@ CObject* CTarget::DetectFriendObject(Math::Point pos) CObject* target = obj; if ( obj->Implements(ObjectInterfaceType::PowerContainer) && IsObjectBeingTransported(obj) ) { - target = dynamic_cast(obj)->GetTransporter(); + target = dynamic_cast(*obj).GetTransporter(); } if ( !target->GetDetectable() ) continue; if ( target->GetProxyActivate() ) continue; - if ( target->Implements(ObjectInterfaceType::Controllable) && dynamic_cast(target)->GetSelect() ) continue; - if ( !target->Implements(ObjectInterfaceType::Controllable) || !dynamic_cast(target)->GetSelectable() ) continue; + if ( target->Implements(ObjectInterfaceType::Controllable) && dynamic_cast(*target).GetSelect() ) continue; + if ( !target->Implements(ObjectInterfaceType::Controllable) || !dynamic_cast(*target).GetSelectable() ) continue; if (!target->Implements(ObjectInterfaceType::Old)) continue; // TODO: To be removed after COldObjectInterface is gone diff --git a/src/ui/displayinfo.cpp b/src/ui/displayinfo.cpp index 107e6b07..09f6d513 100644 --- a/src/ui/displayinfo.cpp +++ b/src/ui/displayinfo.cpp @@ -109,7 +109,7 @@ bool CDisplayInfo::EventProcess(const Event &event) if ( m_toto != nullptr ) { assert(m_toto->Implements(ObjectInterfaceType::Movable)); - CMotionToto* toto = static_cast(dynamic_cast(m_toto)->GetMotion()); + CMotionToto* toto = static_cast(dynamic_cast(*m_toto).GetMotion()); assert(toto != nullptr); toto->SetMousePos(event.mousePos); } @@ -449,7 +449,7 @@ void CDisplayInfo::StartDisplayInfo(std::string filename, int index, bool bSoluc m_toto->SetDrawFront(true); assert(m_toto->Implements(ObjectInterfaceType::Movable)); - CMotionToto* toto = static_cast(dynamic_cast(m_toto)->GetMotion()); + CMotionToto* toto = static_cast(dynamic_cast(*m_toto).GetMotion()); assert(toto != nullptr); toto->StartDisplayInfo(); } @@ -840,7 +840,7 @@ void CDisplayInfo::StopDisplayInfo() if ( m_toto != nullptr ) { assert(m_toto->Implements(ObjectInterfaceType::Movable)); - CMotionToto* toto = static_cast(dynamic_cast(m_toto)->GetMotion()); + CMotionToto* toto = static_cast(dynamic_cast(*m_toto).GetMotion()); assert(toto != nullptr); toto->StopDisplayInfo(); } diff --git a/src/ui/displaytext.cpp b/src/ui/displaytext.cpp index 58d085f5..b21263b4 100644 --- a/src/ui/displaytext.cpp +++ b/src/ui/displaytext.cpp @@ -258,7 +258,7 @@ void CDisplayText::DisplayText(const char *text, Math::Vector goal, float height if ( toto != nullptr ) { assert(toto->Implements(ObjectInterfaceType::Movable)); - motion = dynamic_cast(toto)->GetMotion(); + motion = dynamic_cast(*toto).GetMotion(); if ( type == TT_ERROR ) { diff --git a/src/ui/mainshort.cpp b/src/ui/mainshort.cpp index a8fbbe29..9e2a51a0 100644 --- a/src/ui/mainshort.cpp +++ b/src/ui/mainshort.cpp @@ -150,7 +150,7 @@ bool CMainShort::CreateShortcuts() for (CObject* pObj : CObjectManager::GetInstancePointer()->GetAllObjects()) { if ( !pObj->GetDetectable() ) continue; - if ( pObj->Implements(ObjectInterfaceType::Controllable) && !dynamic_cast(pObj)->GetSelectable() ) continue; + if ( pObj->Implements(ObjectInterfaceType::Controllable) && !dynamic_cast(*pObj).GetSelectable() ) continue; if ( pObj->GetProxyActivate() ) continue; int icon = GetShortcutIcon(pObj->GetType()); @@ -274,9 +274,9 @@ bool CMainShort::UpdateShortcuts() if ( pc != nullptr ) { assert(m_shortcuts[i]->Implements(ObjectInterfaceType::Controllable)); - pc->SetState(STATE_CHECK, dynamic_cast(m_shortcuts[i])->GetSelect()); - pc->SetState(STATE_RUN, m_shortcuts[i]->Implements(ObjectInterfaceType::Programmable) && dynamic_cast(m_shortcuts[i])->IsProgram()); - pc->SetState(STATE_DAMAGE, dynamic_cast(m_shortcuts[i])->IsDamaging()); + pc->SetState(STATE_CHECK, dynamic_cast(*m_shortcuts[i]).GetSelect()); + pc->SetState(STATE_RUN, m_shortcuts[i]->Implements(ObjectInterfaceType::Programmable) && dynamic_cast(*m_shortcuts[i]).IsProgram()); + pc->SetState(STATE_DAMAGE, dynamic_cast(*m_shortcuts[i]).IsDamaging()); } } return true; diff --git a/src/ui/object_interface.cpp b/src/ui/object_interface.cpp index 834523e5..22e56718 100644 --- a/src/ui/object_interface.cpp +++ b/src/ui/object_interface.cpp @@ -595,7 +595,7 @@ bool CObjectInterface::EventProcess(const Event &event) ps = static_cast< CSlider* >(pw->SearchControl(EVENT_OBJECT_DIMSHIELD)); if ( ps != nullptr ) { - dynamic_cast(m_object)->SetShieldRadius((ps->GetVisibleValue()-(RADIUS_SHIELD_MIN/g_unit))/((RADIUS_SHIELD_MAX-RADIUS_SHIELD_MIN)/g_unit)); + dynamic_cast(*m_object).SetShieldRadius((ps->GetVisibleValue()-(RADIUS_SHIELD_MIN/g_unit))/((RADIUS_SHIELD_MAX-RADIUS_SHIELD_MIN)/g_unit)); } } } @@ -1826,7 +1826,7 @@ void CObjectInterface::UpdateInterface() ps = static_cast< CSlider* >(pw->SearchControl(EVENT_OBJECT_DIMSHIELD)); if ( ps != nullptr ) { - ps->SetVisibleValue((RADIUS_SHIELD_MIN/g_unit)+dynamic_cast(m_object)->GetShieldRadius()*((RADIUS_SHIELD_MAX-RADIUS_SHIELD_MIN)/g_unit)); + ps->SetVisibleValue((RADIUS_SHIELD_MIN/g_unit)+dynamic_cast(*m_object).GetShieldRadius()*((RADIUS_SHIELD_MAX-RADIUS_SHIELD_MIN)/g_unit)); } } From 05de2baef5b6d4fc63ee63913222623079d06f6f Mon Sep 17 00:00:00 2001 From: MrSimbax Date: Sun, 20 Sep 2020 21:22:05 +0200 Subject: [PATCH 74/98] Fix crashes in SatCom on some \button characters The issue is that the \button fragments in SatCom are replaced with invalid UTF-8 bytes, hence those bytes need to be handled as a special case when checking for UTF-8 character length. When the text is processed e.g. in `Gfx::CText::Justify`, there are generally two arrays: `text` and `format`. The second one is interpreted as a font for a given character, e.g. `text[i]` has font `format[i]`. Now, in the loops the index for `text` is increased by the length of the character, e.g. 1 to 4 bytes, whereas index for `format` is only incremented. It seems there's an assumption that `format` treats multibyte characters as one byte, which doesn't seem to be true by looking at the process of filling up the `format` array. This can result in using wrong font e.g. FONT_SATCOM for the \button character which should be FONT_BUTTON, hence the `StrUtils::Utf8CharSizeAt` method complains about unexpected continuation byte via exception, causing the crash. Incrementing the index by the UTF-8 length seems to have fixed the issue. However, I am not sure if I haven't broken anything else by this and if I analyzed the intended behaviour correctly. Gfx::CText needs a major refactor IMHO. --- src/graphics/engine/text.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/graphics/engine/text.cpp b/src/graphics/engine/text.cpp index fd946cca..fef37333 100644 --- a/src/graphics/engine/text.cpp +++ b/src/graphics/engine/text.cpp @@ -459,7 +459,7 @@ float CText::GetStringWidth(const std::string &text, width += GetCharWidth(ch, font, size, width); index += len; - fmtIndex++; + fmtIndex += len; } return width; @@ -607,7 +607,7 @@ int CText::Justify(const std::string &text, std::vector::iterator } index += len; - fmtIndex++; + fmtIndex += len; } return index; @@ -685,7 +685,7 @@ int CText::Detect(const std::string &text, std::vector::iterator f pos += width; index += len; - fmtIndex++; + fmtIndex += len; } return index; From 10ec454f6bf8f9ded44ebc0a08a987b6e6e342fc Mon Sep 17 00:00:00 2001 From: Fiftytwo Date: Thu, 31 Dec 2020 05:00:33 +0100 Subject: [PATCH 75/98] Fix Target research() executing in ResearchCenter --- src/script/scriptfunc.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/script/scriptfunc.cpp b/src/script/scriptfunc.cpp index 6db8f34c..b72ef470 100644 --- a/src/script/scriptfunc.cpp +++ b/src/script/scriptfunc.cpp @@ -595,7 +595,8 @@ bool CScriptFunctions::rResearch(CBotVar* var, CBotVar* result, int& exception, { bool ok = false; if ( type == RESEARCH_iPAW || - type == RESEARCH_iGUN ) + type == RESEARCH_iGUN || + type == RESEARCH_TARGET ) { if ( center->GetType() != OBJECT_LABO ) err = ERR_WRONG_OBJ; From c336a67afae2030b38b2ab86e2d6da648892bb1e Mon Sep 17 00:00:00 2001 From: jakac Date: Sun, 3 Jan 2021 15:30:41 +0100 Subject: [PATCH 76/98] Fix MSVC building issues by correcting CMakeLists.txt --- src/CMakeLists.txt | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8dc9af86..3c5f4063 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -48,25 +48,30 @@ elseif(PLATFORM_WINDOWS) if(${MSVC_STATIC}) if (${OPENAL_SOUND}) - find_library(FLAC_LIBRARY NAMES flac.lib) - find_library(VORBIS_LIBRARY NAMES vorbis.lib) - find_library(VORBISENC_LIBRARY NAMES vorbisenc.lib) - find_library(OGG_LIBRARY NAMES ogg.lib) + find_library(FLAC_LIBRARY NAMES flac) + find_library(VORBIS_LIBRARY NAMES vorbis) + find_library(VORBISENC_LIBRARY NAMES vorbisenc) + find_library(OGG_LIBRARY NAMES ogg) + find_library(OPUS_LIBRARY NAMES opus) set(OPENAL_MSVC_LIBS ${FLAC_LIBRARY} ${VORBIS_LIBRARY} ${VORBISENC_LIBRARY} ${OGG_LIBRARY} + ${OPUS_LIBRARY} ) endif() - find_library(BZ2_LIBRARY NAMES bz2.lib) - find_library(JPEG_LIBRARY NAMES jpeg.lib) - find_library(TIFF_LIBRARY NAMES tiff.lib) - find_library(LZMA_LIBRARY NAMES lzma.lib) - find_library(FREETYPE_LIBRARY NAMES freetype.lib) - find_library(ICONV_LIBRARY NAMES libiconv.lib) - find_library(CHARSET_LIBRARY NAMES libcharset.lib) + find_library(BZ2_LIBRARY NAMES bz2) + find_library(JPEG_LIBRARY NAMES jpeg) + find_library(TIFF_LIBRARY NAMES tiff) + find_library(LZMA_LIBRARY NAMES lzma) + find_library(FREETYPE_LIBRARY NAMES freetype) + find_library(ICONV_LIBRARY NAMES iconv) + find_library(CHARSET_LIBRARY NAMES charset) + find_library(BROTLICOMMON_LIBRARY NAMES brotlicommon-static) + find_library(BROTLIENC_LIBRARY NAMES brotlienc-static) + find_library(BROTLIDEC_LIBRARY NAMES brotlidec-static) set(MSVC_LIBS ${LIBINTL_LIBRARY} ${OPENAL_MSVC_LIBS} @@ -77,6 +82,9 @@ elseif(PLATFORM_WINDOWS) ${FREETYPE_LIBRARY} ${ICONV_LIBRARY} ${CHARSET_LIBRARY} + ${BROTLICOMMON_LIBRARY} + ${BROTLIENC_LIBRARY} + ${BROTLIDEC_LIBRARY} winmm.lib dxguid.lib imm32.lib From 71ff89a803133c944a78ec66debc7b9fe6e3576a Mon Sep 17 00:00:00 2001 From: MrSimbax Date: Sun, 7 Feb 2021 12:47:32 +0100 Subject: [PATCH 77/98] Remove vsync disable/enable loop (fix #1383) Also a small refactor due to repeated code. The vsync flag in m_engine is now synchronized with the SDL state during initial configuration of CApp. --- src/app/app.cpp | 73 ++++++++++++++++++++++--------------------------- src/app/app.h | 3 ++ 2 files changed, 35 insertions(+), 41 deletions(-) diff --git a/src/app/app.cpp b/src/app/app.cpp index ad5d02cb..47569c0a 100644 --- a/src/app/app.cpp +++ b/src/app/app.cpp @@ -115,7 +115,8 @@ CApplication::CApplication(CSystemUtils* systemUtils) m_configFile(MakeUnique()), m_input(MakeUnique()), m_pathManager(MakeUnique(systemUtils)), - m_modManager(MakeUnique(this, m_pathManager.get())) + m_modManager(MakeUnique(this, m_pathManager.get())), + m_engine(MakeUnique(this, m_systemUtils)) { m_exitCode = 0; m_active = false; @@ -693,8 +694,6 @@ bool CApplication::Create() } // Create the 3D engine - m_engine = MakeUnique(this, m_systemUtils); - m_engine->SetDevice(m_device.get()); if (! m_engine->Create() ) @@ -850,24 +849,9 @@ bool CApplication::CreateVideoSurface() int vsync = 0; if (GetConfigFile().GetIntProperty("Setup", "VSync", vsync)) { - while (SDL_GL_SetSwapInterval(vsync) == -1) - { - switch(vsync) - { - case -1: //failed with adaptive sync? - GetLogger()->Warn("Adaptive sync not supported.\n"); - vsync = 1; - break; - case 1: //failed with VSync enabled? - GetLogger()->Warn("Couldn't enable VSync.\n"); - vsync = 0; - break; - case 0: //failed with VSync disabled? - GetLogger()->Warn("Couldn't disable VSync.\n"); - vsync = 1; - break; - } - } + m_engine->SetVSync(vsync); + TryToSetVSync(); + vsync = m_engine->GetVSync(); GetConfigFile().SetIntProperty("Setup", "VSync", vsync); GetLogger()->Info("Using Vsync: %s\n", (vsync == -1 ? "adaptive" : (vsync ? "true" : "false"))); @@ -876,6 +860,32 @@ bool CApplication::CreateVideoSurface() return true; } +void CApplication::TryToSetVSync() +{ + int vsync = m_engine->GetVSync(); + int result = SDL_GL_SetSwapInterval(vsync); + if (result == -1) + { + switch (vsync) + { + case -1: + GetLogger()->Warn("Adaptive sync not supported: %s\n", SDL_GetError()); + m_engine->SetVSync(1); + TryToSetVSync(); + break; + case 1: + GetLogger()->Warn("Couldn't enable VSync: %s\n", SDL_GetError()); + m_engine->SetVSync(0); + TryToSetVSync(); + break; + case 0: + GetLogger()->Warn("Couldn't disable VSync: %s\n", SDL_GetError()); + m_engine->SetVSync(SDL_GL_GetSwapInterval()); + break; + } + } +} + bool CApplication::ChangeVideoConfig(const Gfx::DeviceConfig &newConfig) { m_deviceConfig = newConfig; @@ -884,26 +894,7 @@ bool CApplication::ChangeVideoConfig(const Gfx::DeviceConfig &newConfig) SDL_SetWindowSize(m_private->window, m_deviceConfig.size.x, m_deviceConfig.size.y); SDL_SetWindowFullscreen(m_private->window, m_deviceConfig.fullScreen ? SDL_WINDOW_FULLSCREEN : 0); - int vsync = m_engine->GetVSync(); - while (SDL_GL_SetSwapInterval(vsync) == -1) - { - switch(vsync) - { - case -1: //failed with adaptive sync? - GetLogger()->Warn("Adaptive sync not supported.\n"); - vsync = 1; - break; - case 1: //failed with VSync enabled? - GetLogger()->Warn("Couldn't enable VSync.\n"); - vsync = 0; - break; - case 0: //failed with VSync disabled? - GetLogger()->Warn("Couldn't disable VSync.\n"); - vsync = 1; - break; - } - } - m_engine->SetVSync(vsync); + TryToSetVSync(); m_device->ConfigChanged(m_deviceConfig); diff --git a/src/app/app.h b/src/app/app.h index af385cf2..d238bde9 100644 --- a/src/app/app.h +++ b/src/app/app.h @@ -288,6 +288,9 @@ public: protected: //! Creates the window's SDL_Surface bool CreateVideoSurface(); + //! Tries to set the SDL vsync state desired by the 3D engine + //! The final state of SDL vsync is set in the 3D engine afterwards + void TryToSetVSync(); //! Processes the captured SDL event to Event struct Event ProcessSystemEvent(); From a7aaa07356e99099fb98500530fb037c1f5707d5 Mon Sep 17 00:00:00 2001 From: MrSimbax Date: Sun, 7 Feb 2021 12:50:13 +0100 Subject: [PATCH 78/98] Update vsync list after user interaction The vsync may immediately fallback to another option after change from the user so the UI should reflect that. Todo: show a popup in UI informing the user why their desired vsync option couldn't be set. Right now the error message is visible only from the logs. --- src/ui/screen/screen_setup_display.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/ui/screen/screen_setup_display.cpp b/src/ui/screen/screen_setup_display.cpp index 219c7f29..f465a488 100644 --- a/src/ui/screen/screen_setup_display.cpp +++ b/src/ui/screen/screen_setup_display.cpp @@ -293,6 +293,7 @@ void CScreenSetupDisplay::UpdateApply() CWindow* pw; CButton* pb; CList* pl; + CList* pvl; CCheck* pc; int sel2; bool bFull; @@ -309,6 +310,22 @@ void CScreenSetupDisplay::UpdateApply() pc = static_cast(pw->SearchControl(EVENT_INTERFACE_FULL)); bFull = pc->TestState(STATE_CHECK); + pvl = static_cast(pw->SearchControl(EVENT_INTERFACE_VSYNC)); + if (pvl == nullptr) return; + + switch (m_engine->GetVSync()) + { + case -1: //Adaptive? + pvl->SetSelect(1); + break; + case 0: //Off? + pvl->SetSelect(0); + break; + case 1: //On? + pvl->SetSelect(2); + break; + } + if ( sel2 == m_setupSelMode && bFull == m_setupFull ) { From 9a0468510141e8d5a584b1b7dd4f43a121dc45c7 Mon Sep 17 00:00:00 2001 From: MrSimbax Date: Sun, 7 Feb 2021 13:03:12 +0100 Subject: [PATCH 79/98] Fix compile error --- src/app/app.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/app.cpp b/src/app/app.cpp index 47569c0a..8e43780a 100644 --- a/src/app/app.cpp +++ b/src/app/app.cpp @@ -112,11 +112,11 @@ struct ApplicationPrivate CApplication::CApplication(CSystemUtils* systemUtils) : m_systemUtils(systemUtils), m_private(MakeUnique()), + m_engine(MakeUnique(this, m_systemUtils)), m_configFile(MakeUnique()), m_input(MakeUnique()), m_pathManager(MakeUnique(systemUtils)), - m_modManager(MakeUnique(this, m_pathManager.get())), - m_engine(MakeUnique(this, m_systemUtils)) + m_modManager(MakeUnique(this, m_pathManager.get())) { m_exitCode = 0; m_active = false; From 404d2dbeb1d8cb2e9a6748038bb48160f1aac5a2 Mon Sep 17 00:00:00 2001 From: MrSimbax Date: Sun, 7 Feb 2021 13:38:29 +0100 Subject: [PATCH 80/98] Fix segfault in CApp UT I moved m_engine creation to the constructor. However, it is not complete until after calling m_engine->Create(). The UT segfault because the pointer is not null and destructor calls m_engine->Destroy() on an incomplete object. (Yes, UTs test incomplete SUT.) So I moved back the m_engine creation to CApp::Create() but before the SDL initialization as m_engine holds the flag for vsync. --- src/app/app.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/app.cpp b/src/app/app.cpp index 8e43780a..1e4515ed 100644 --- a/src/app/app.cpp +++ b/src/app/app.cpp @@ -112,7 +112,6 @@ struct ApplicationPrivate CApplication::CApplication(CSystemUtils* systemUtils) : m_systemUtils(systemUtils), m_private(MakeUnique()), - m_engine(MakeUnique(this, m_systemUtils)), m_configFile(MakeUnique()), m_input(MakeUnique()), m_pathManager(MakeUnique(systemUtils)), @@ -550,6 +549,8 @@ bool CApplication::Create() /* SDL initialization sequence */ + // Creating the m_engine now because it holds the vsync flag + m_engine = MakeUnique(this, m_systemUtils); Uint32 initFlags = SDL_INIT_VIDEO | SDL_INIT_TIMER; From 9c91fd1e520dff4234b490754790064154cb0e29 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Mon, 22 Feb 2021 10:43:07 +0100 Subject: [PATCH 81/98] Replace custom download script with dawidd6/action-download-artifact --- .github/workflows/lint.yml | 58 +++++++------------------------------- 1 file changed, 10 insertions(+), 48 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index c28c0da5..08dd8d45 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -15,59 +15,20 @@ jobs: run: sudo apt-get update && sudo apt-get install -y --no-install-recommends build-essential cmake libsdl2-dev libsdl2-image-dev libsdl2-ttf-dev libsndfile1-dev libvorbis-dev libogg-dev libpng-dev libglew-dev libopenal-dev libboost-dev libboost-system-dev libboost-filesystem-dev libboost-regex-dev libphysfs-dev gettext git po4a vorbis-tools librsvg2-bin xmlstarlet - name: Download colobot-lint dependencies run: sudo apt-get install -y --no-install-recommends clang-3.6 libtinyxml2.6.2v5 - - run: pip install requests - run: mkdir -p /tmp/colobot-lint - name: Download colobot-lint - working-directory: /tmp/colobot-lint - shell: python - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - REPO_NAME: colobot/colobot-lint - BRANCH_NAME: master - ARTIFACT_NAME: colobot-lint - run: | - import os - import requests - - # How there can be no builtin action to download the latest artifact from another repo?! - - s = requests.Session() - s.headers.update({ - 'Authorization': 'token ' + os.environ['GITHUB_TOKEN'], - 'Accept': 'application/vnd.github.v3+json' - }) - - r = s.get("https://api.github.com/repos/" + os.environ['REPO_NAME'] + "/actions/runs", params={'branch': os.environ['BRANCH_NAME'], 'event': 'push', 'status': 'success'}) - r.raise_for_status() - - # Querying for "dev" returns all branches that have "dev" anywhere in the name... is that a GitHub bug or intended behaviour? - runs = list(filter(lambda x: x['head_branch'] == os.environ['BRANCH_NAME'], r.json()['workflow_runs'])) - if len(runs) == 0: - raise Exception('No valid run found') - run = runs[0] - print("Using colobot-lint from run #{} ({}) for commit {}".format(run['run_number'], run['id'], run['head_sha'])) - - r = s.get(run['artifacts_url']) - r.raise_for_status() - artifacts = list(filter(lambda x: x['name'] == os.environ['ARTIFACT_NAME'], r.json()['artifacts'])) - if len(artifacts) != 1: - raise Exception('Artifact not found') - artifact = artifacts[0] - print(artifact['archive_download_url']) - - r = s.get(artifact['archive_download_url'], stream=True) - r.raise_for_status() - with open(os.environ['ARTIFACT_NAME'] + '.zip', 'wb') as f: - for block in r.iter_content(1024): - f.write(block) - print("Download finished") + uses: dawidd6/action-download-artifact@v2 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + repo: colobot/colobot-lint + branch: master + workflow: build.yml + workflow_conclusion: success + name: colobot-lint + path: /tmp/colobot-lint/archive - name: Unpack colobot-lint working-directory: /tmp/colobot-lint run: | - # Unzip the archive - mkdir archive; cd archive - unzip ../colobot-lint.zip - cd .. # Workaround for Clang not finding system headers mkdir ./bin mv ./archive/build/colobot-lint ./bin/ @@ -118,6 +79,7 @@ jobs: with: name: HTML results path: build/html_report + - run: pip install requests - name: Send linter results to GitHub shell: python env: From 9f2f7780a4755ade45fc6769b59aee4e9ec2974d Mon Sep 17 00:00:00 2001 From: krzys-h Date: Mon, 22 Feb 2021 11:12:21 +0100 Subject: [PATCH 82/98] Safely upload linter results from forks to GitHub This makes lint results from pull requests appear as GitHub checks similarly to how pull requests from branches are able to work Based on https://securitylab.github.com/research/github-actions-preventing-pwn-requests --- .github/workflows/lint.yml | 72 ++++++++--------------- .github/workflows/lint_upload_results.yml | 67 +++++++++++++++++++++ 2 files changed, 92 insertions(+), 47 deletions(-) create mode 100644 .github/workflows/lint_upload_results.yml diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 08dd8d45..967b4c91 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -79,16 +79,12 @@ jobs: with: name: HTML results path: build/html_report - - run: pip install requests - - name: Send linter results to GitHub + - name: Generate GitHub annotations JSON and process check result shell: python - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - ACTUALLY_SEND: ${{ github.event.type != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} run: | import os import sys - import requests + import json import xml.etree.ElementTree as ET OVERALL_STABLE_RULES=[ @@ -141,18 +137,6 @@ jobs: "whitespace", ] - # None of the available actions seem to do what I want, they all do stupid things like adding another check... let's just do it manually - # GitHub also doesn't seem to provide you with the check suite or check run ID, so we have to get it from the action ID via the API - s = requests.Session() - s.headers.update({ - 'Authorization': 'token ' + os.environ['GITHUB_TOKEN'], - 'Accept': 'application/vnd.github.antiope-preview+json' # Annotations are still technically a preview feature of the API - }) - action_run = s.get(os.environ['GITHUB_API_URL'] + "/repos/" + os.environ['GITHUB_REPOSITORY'] + "/actions/runs/" + os.environ['GITHUB_RUN_ID']).json() - check_suite = s.get(action_run['check_suite_url']).json() - check_suite_runs = s.get(check_suite['check_runs_url']).json() - check_run = check_suite_runs['check_runs'][0] # NOTE: This assumes that the 'lint' job is the first one in the workflow. You could find it by name if you really wanted. - def we_care_about(file_name, type): if 'CBot' in file_name: return type in OVERALL_STABLE_RULES @@ -161,6 +145,7 @@ jobs: results = ET.parse('build/colobot_lint_report.xml') annotations = [] + stable_annotations = [] for error in results.find('errors').findall('error'): location = error.find('location') file_name = os.path.relpath(location.get('file'), os.environ['GITHUB_WORKSPACE']) @@ -175,42 +160,35 @@ jobs: elif severity == 'information': gh_severity = 'notice' - if not we_care_about(file_name, type): - # don't send the unstable rules to github at all as there are way too many of them and it would overload the API rate limit - continue - - print('{}:{}: [{}] {}'.format(file_name, line_num, type, msg)) - - annotations.append({ + annotation = { 'path': file_name, 'start_line': line_num, 'end_line': line_num, 'annotation_level': gh_severity, 'title': type, 'message': msg - }) + } + annotations.append(annotation) - summary = 'colobot-lint found {} issues'.format(len(annotations)) - all_ok = len(annotations) == 0 + if we_care_about(file_name, type): + # don't send the unstable rules to github at all as there are way too many of them and it would overload the API rate limit + stable_annotations.append(annotation) + print('{}:{}: [{}] {}'.format(file_name, line_num, type, msg)) + + summary = 'colobot-lint found {} issues'.format(len(stable_annotations)) + all_ok = len(stable_annotations) == 0 print('Conclusion: {}'.format(summary)) - if os.environ['ACTUALLY_SEND'] != "true": - print('Skip uploading the results as annotations because tokens from forks are readonly and there seems to be no way to do it. Blame GitHub Actions devs.') - else: - # Annotations have to be sent in batches of 50 - first = True - while first or len(annotations) > 0: - first = False - to_send = annotations[:50] - annotations = annotations[50:] - data = { - 'output': { - 'title': summary, - 'summary': summary, - 'annotations': to_send - } - } - r = s.patch(check_run['url'], json=data) - r.raise_for_status() - + with open("build/annotations.json", "w") as f: + json.dump(annotations, f, indent=4) + with open("build/stable_annotations.json", "w") as f: + json.dump(stable_annotations, f, indent=4) sys.exit(0 if all_ok else 1) + - name: Upload results (JSON) + uses: actions/upload-artifact@v2 + with: + name: JSON results + path: | + build/annotations.json + build/stable_annotations.json + if: ${{ always() }} diff --git a/.github/workflows/lint_upload_results.yml b/.github/workflows/lint_upload_results.yml new file mode 100644 index 00000000..3adb3c54 --- /dev/null +++ b/.github/workflows/lint_upload_results.yml @@ -0,0 +1,67 @@ +name: Linter upload results + +# Upload linter results after succesful linter run +# This is done in a separate workflow to safely use the read-write GitHub token +# See https://securitylab.github.com/research/github-actions-preventing-pwn-requests + +on: + workflow_run: + workflows: ["Linter"] + types: + - completed + +jobs: + lint_upload: + runs-on: ubuntu-16.04 + steps: + - run: pip install requests + - name: Download linter results + uses: dawidd6/action-download-artifact@v2 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + workflow: lint.yml + run_id: ${{ github.event.workflow_run.id }} + name: JSON results + path: results + - name: Send linter results to GitHub + shell: python + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + RUN_ID: ${{ github.event.workflow_run.id }} + run: | + import os + import json + import requests + + # Load the results from the lint job artifact + with open("results/stable_annotations.json", "r") as f: + annotations = json.load(f) + summary = 'colobot-lint found {} issues'.format(len(annotations)) + + # None of the available actions seem to do what I want, they all do stupid things like adding another check... let's just do it manually + # GitHub also doesn't seem to provide you with the check suite or check run ID, so we have to get it from the action ID via the API + s = requests.Session() + s.headers.update({ + 'Authorization': 'token ' + os.environ['GITHUB_TOKEN'], + 'Accept': 'application/vnd.github.antiope-preview+json' # Annotations are still technically a preview feature of the API + }) + action_run = s.get(os.environ['GITHUB_API_URL'] + "/repos/" + os.environ['GITHUB_REPOSITORY'] + "/actions/runs/" + os.environ['RUN_ID']).json() + check_suite = s.get(action_run['check_suite_url']).json() + check_suite_runs = s.get(check_suite['check_runs_url']).json() + check_run = check_suite_runs['check_runs'][0] # NOTE: This assumes that the 'lint' job is the first one in the workflow. You could find it by name if you really wanted. + + # Annotations have to be sent in batches of 50 + first = True + while first or len(annotations) > 0: + first = False + to_send = annotations[:50] + annotations = annotations[50:] + data = { + 'output': { + 'title': summary, + 'summary': summary, + 'annotations': to_send + } + } + r = s.patch(check_run['url'], json=data) + r.raise_for_status() From f5519f8936b919423e36a1f4f6d72b7a12facbc9 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Mon, 22 Feb 2021 11:55:51 +0100 Subject: [PATCH 83/98] Send comment when pull request targets the wrong branch --- .github/workflows/verify-pr-target.yml | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/.github/workflows/verify-pr-target.yml b/.github/workflows/verify-pr-target.yml index 09cadb19..c5f388d7 100644 --- a/.github/workflows/verify-pr-target.yml +++ b/.github/workflows/verify-pr-target.yml @@ -1,14 +1,21 @@ name: Verify pull request target -on: [pull_request] +on: [pull_request_target] jobs: check_pr_target: runs-on: ubuntu-latest steps: - - name: Wrong pull request target - run: echo "This pull request targets the master branch. Please edit the pull request to target dev." && exit 1 + - name: Send comment if wrong pull request target if: github.base_ref == 'master' + uses: peter-evans/create-or-update-comment@v1 + with: + issue-number: ${{ github.event.number }} + body: | + Hey! This pull request targets the `master` branch. You should probably target `dev` instead. Make sure to read the [contributing guidelines](https://github.com/colobot/colobot/blob/master/CONTRIBUTING.md#submitting-pull-requests) and [edit the target branch if necessary](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/changing-the-base-branch-of-a-pull-request). + - name: Wrong pull request target + if: github.base_ref == 'master' + run: echo "This pull request targets the master branch. Please edit the pull request to target dev." && exit 1 - name: Correct pull request target + if: github.base_ref != 'master' run: echo "This pull request targets the correct branch." && exit 0 - if: github.base_ref != 'master' \ No newline at end of file From 0b948b655e8541922bfd0e3f087b453e52c171d5 Mon Sep 17 00:00:00 2001 From: tomangelo2 Date: Sun, 21 Mar 2021 15:17:28 +0100 Subject: [PATCH 84/98] Add missing library in MSYS2 instruction --- INSTALL-MSYS2.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/INSTALL-MSYS2.md b/INSTALL-MSYS2.md index f35634f3..bc5f90d1 100644 --- a/INSTALL-MSYS2.md +++ b/INSTALL-MSYS2.md @@ -110,7 +110,7 @@ Easy, isn't it? If you are lazy, you can just use this one-line command, although there is no guarantee it will work or install everything (might be out of date): ```sh -pacman -S mingw-w64-i686-boost mingw-w64-i686-glew mingw-w64-i686-libpng gettext mingw-w64-i686-gettext mingw-w64-i686-libpng mingw-w64-i686-libsndfile mingw-w64-i686-libvorbis mingw-w64-i686-libogg mingw-w64-i686-openal mingw-w64-i686-SDL2 mingw-w64-i686-SDL2_image mingw-w64-i686-SDL2_ttf +pacman -S mingw-w64-i686-boost mingw-w64-i686-glew mingw-w64-i686-libpng gettext mingw-w64-i686-gettext mingw-w64-i686-libpng mingw-w64-i686-libsndfile mingw-w64-i686-libvorbis mingw-w64-i686-libogg mingw-w64-i686-openal mingw-w64_i686-physfs mingw-w64-i686-SDL2 mingw-w64-i686-SDL2_image mingw-w64-i686-SDL2_ttf ``` You should now have everything set up and working. You can close all instances of MSYS2 and autorebase to ensure everything installed properly. From dbd9db86a633efa8cf41338b735e45a7115ce35c Mon Sep 17 00:00:00 2001 From: Fiftytwo Date: Sun, 21 Mar 2021 22:10:42 +0100 Subject: [PATCH 85/98] Update data submodule --- data | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data b/data index 611cbfdd..67d378f8 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 611cbfdd079e97a71f97810636f2ab2358cb4eeb +Subproject commit 67d378f8a940acb23e1426c55798f0f30239ca2a From cdb63e2a8cdb9d4fad070571ac890bb173fb1e44 Mon Sep 17 00:00:00 2001 From: Fiftytwo Date: Tue, 30 Mar 2021 20:51:17 +0200 Subject: [PATCH 86/98] Update data submodule --- data | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data b/data index 67d378f8..87aeb32a 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 67d378f8a940acb23e1426c55798f0f30239ca2a +Subproject commit 87aeb32afbc7e4135a5a3533998a9274d9de30a3 From 993a6adf6e9874be7c36d6e1776767d687f92628 Mon Sep 17 00:00:00 2001 From: melex750 Date: Fri, 11 Jun 2021 22:44:20 -0400 Subject: [PATCH 87/98] Fix inherited data members not being saved * Removed erroneous 'parent instance' from CBotVarClass. * Fixed output of CBVarClass::GetValString() --- src/CBot/CBotStack.cpp | 17 +++++--- src/CBot/CBotVar/CBotVarClass.cpp | 64 ++++++++++++++++--------------- src/CBot/CBotVar/CBotVarClass.h | 2 - test/unit/CBot/CBot_test.cpp | 64 +++++++++++++++++++++++++++++++ 4 files changed, 108 insertions(+), 39 deletions(-) diff --git a/src/CBot/CBotStack.cpp b/src/CBot/CBotStack.cpp index d6377c7b..25e895d7 100644 --- a/src/CBot/CBotStack.cpp +++ b/src/CBot/CBotStack.cpp @@ -908,13 +908,18 @@ bool CBotVar::RestoreState(std::istream &istr, CBotVar* &pVar) if (isClass && p == nullptr) // set id for each item in this instance { - CBotVar* pVars = pNew->GetItemList(); - CBotVar* pv = pNew->GetClass()->GetVar(); - while (pVars != nullptr && pv != nullptr) + CBotClass* pClass = pNew->GetClass(); + CBotVar* pVars = (static_cast(pNew))->m_pVar; + while (pClass != nullptr && pVars != nullptr) { - pVars->m_ident = pv->m_ident; - pv = pv->GetNext(); - pVars = pVars->GetNext(); + CBotVar* pv = pClass->GetVar(); + while (pVars != nullptr && pv != nullptr) + { + pVars->m_ident = pv->m_ident; + pVars = pVars->m_next; + pv = pv->m_next; + } + pClass = pClass->GetParent(); } } diff --git a/src/CBot/CBotVar/CBotVarClass.cpp b/src/CBot/CBotVar/CBotVarClass.cpp index 98d95f44..0e14e077 100644 --- a/src/CBot/CBotVar/CBotVarClass.cpp +++ b/src/CBot/CBotVar/CBotVarClass.cpp @@ -54,7 +54,6 @@ CBotVarClass::CBotVarClass(const CBotToken& name, const CBotTypResult& type) : C // official type for this object m_pClass = nullptr; - m_pParent = nullptr; m_binit = InitType::UNDEF; m_bStatic = false; m_mPrivate = ProtectionLevel::Public; @@ -63,14 +62,9 @@ CBotVarClass::CBotVarClass(const CBotToken& name, const CBotTypResult& type) : C m_ItemIdent = type.Eq(CBotTypIntrinsic) ? 0 : CBotVar::NextUniqNum(); // add to the list - m_instances.insert(this); + if (m_ItemIdent != 0) m_instances.insert(this); CBotClass* pClass = type.GetClass(); - if ( pClass != nullptr && pClass->GetParent() != nullptr ) - { - // also creates an instance of the parent class - m_pParent = new CBotVarClass(name, CBotTypResult(type.GetType(), pClass->GetParent()) ); //, nIdent); - } SetClass( pClass ); @@ -82,11 +76,8 @@ CBotVarClass::~CBotVarClass( ) if ( m_CptUse != 0 ) assert(0); - if ( m_pParent ) delete m_pParent; - m_pParent = nullptr; - // removes the class list - m_instances.erase(this); + if (m_ItemIdent != 0) m_instances.erase(this); delete m_pVar; } @@ -113,10 +104,6 @@ void CBotVarClass::Copy(CBotVar* pSrc, bool bName) m_binit = p->m_binit; //- m_bStatic = p->m_bStatic; m_pClass = p->m_pClass; - if ( p->m_pParent ) - { - assert(0); // "que faire du pParent"; - } // m_next = nullptr; m_pUserPtr = p->m_pUserPtr; @@ -162,9 +149,11 @@ void CBotVarClass::SetClass(CBotClass* pClass)//, int &nIdent) if (pClass == nullptr) return; - CBotVar* pv = pClass->GetVar(); // first on a list - while ( pv != nullptr ) + CBotVar* pv = nullptr; + while (pClass != nullptr) { + if ( pv == nullptr ) pv = pClass->GetVar(); + if ( pv == nullptr ) { pClass = pClass->GetParent(); continue; } // seeks the maximum dimensions of the table CBotInstr* p = pv->m_LimExpr; // the different formulas if ( p != nullptr ) @@ -214,6 +203,7 @@ void CBotVarClass::SetClass(CBotClass* pClass)//, int &nIdent) if ( m_pVar == nullptr) m_pVar = pn; else m_pVar->AddNext( pn ); pv = pv->GetNext(); + if ( pv == nullptr ) pClass = pClass->GetParent(); } } @@ -246,7 +236,6 @@ CBotVar* CBotVarClass::GetItem(const std::string& name) p = p->GetNext(); } - if ( m_pParent != nullptr ) return m_pParent->GetItem(name); return nullptr; } @@ -261,7 +250,6 @@ CBotVar* CBotVarClass::GetItemRef(int nIdent) p = p->GetNext(); } - if ( m_pParent != nullptr ) return m_pParent->GetItemRef(nIdent); return nullptr; } @@ -311,32 +299,46 @@ std::string CBotVarClass::GetValString() { res = m_pClass->GetName() + std::string("( "); - CBotVarClass* my = this; - while ( my != nullptr ) + CBotClass* pClass = m_pClass; + long prevID = 0; { - CBotVar* pv = my->m_pVar; - while ( pv != nullptr ) + CBotVar* pv = m_pVar; + if (pv != nullptr) while (true) { + if (pv->GetUniqNum() < prevID) + { + pClass = pClass->GetParent(); + if (pClass == nullptr) break; + res += " ) extends "; + res += pClass->GetName(); + res += "( "; + if (pClass->GetVar() == nullptr) continue; + } + + prevID = pv->GetUniqNum(); + res += pv->GetName() + std::string("="); if ( pv->IsStatic() ) { - CBotVar* pvv = my->m_pClass->GetItem(pv->GetName()); - res += pvv->GetValString(); + res += pClass->GetItemRef(prevID)->GetValString(); } else { res += pv->GetValString(); } pv = pv->GetNext(); - if ( pv != nullptr ) res += ", "; + if ( pv == nullptr ) break; + if ( pv->GetUniqNum() > prevID ) res += ", "; } - my = my->m_pParent; - if ( my != nullptr ) + + if (pClass != nullptr) while (true) { - res += ") extends "; - res += my->m_pClass->GetName(); - res += " ("; + pClass = pClass->GetParent(); + if (pClass == nullptr) break; + res += " ) extends "; + res += pClass->GetName(); + res += "( "; } } diff --git a/src/CBot/CBotVar/CBotVarClass.h b/src/CBot/CBotVar/CBotVarClass.h index 6e98f62e..ac462d99 100644 --- a/src/CBot/CBotVar/CBotVarClass.h +++ b/src/CBot/CBotVar/CBotVarClass.h @@ -99,8 +99,6 @@ private: static std::set m_instances; //! Class definition CBotClass* m_pClass; - //! Parent class instance - CBotVarClass* m_pParent; //! Class members CBotVar* m_pVar; //! Reference counter diff --git a/test/unit/CBot/CBot_test.cpp b/test/unit/CBot/CBot_test.cpp index 4f4f37c7..46dbfe81 100644 --- a/test/unit/CBot/CBot_test.cpp +++ b/test/unit/CBot/CBot_test.cpp @@ -747,6 +747,48 @@ TEST_F(CBotUT, ToString) "}\n" ); + ExecuteTest( + "extern void ClassToString_2()\n" + "{\n" + " string s = new TestClass;\n" + " ASSERT(s == \"Pointer to TestClass( )\");\n" + "}\n" + "public class TestClass { /* no fields */ }\n" + ); + + ExecuteTest( + "extern void ClassInheritanceToString()\n" + "{\n" + " string s = new SubClass;\n" + " ASSERT(s == \"Pointer to SubClass( c=7, d=8, e=9 ) extends MidClass( b=4, c=5, d=6 ) extends BaseClass( a=1, b=2, c=3 )\");\n" + "}\n" + "public class BaseClass { int a = 1, b = 2, c = 3; }\n" + "public class MidClass extends BaseClass { int b = 4, c = 5, d = 6; }\n" + "public class SubClass extends MidClass { int c = 7, d = 8, e = 9; }\n" + ); + + ExecuteTest( + "extern void ClassInheritanceToString_2()\n" + "{\n" + " string s = new SubClass;\n" + " ASSERT(s == \"Pointer to SubClass( c=7, d=8, e=9 ) extends MidClass( ) extends BaseClass( a=1, b=2, c=3 )\");\n" + "}\n" + "public class BaseClass { int a = 1, b = 2, c = 3; }\n" + "public class MidClass extends BaseClass { /* no fields */ }\n" + "public class SubClass extends MidClass { int c = 7, d = 8, e = 9; }\n" + ); + + ExecuteTest( + "extern void ClassInheritanceToString_3()\n" + "{\n" + " string s = new SubClass;\n" + " ASSERT(s == \"Pointer to SubClass( c=7, d=8, e=9 ) extends MidClass( ) extends BaseClass( )\");\n" + "}\n" + "public class BaseClass { /* no fields */ }\n" + "public class MidClass extends BaseClass { /* no fields */ }\n" + "public class SubClass extends MidClass { int c = 7, d = 8, e = 9; }\n" + ); + // TODO: IntrinsicClassToString ? (e.g. point) } @@ -3197,3 +3239,25 @@ TEST_F(CBotUT, ClassTestPrivateMethod) CBotErrPrivate ); } + +TEST_F(CBotUT, ClassTestSaveInheritedMembers) +{ + auto publicProgram = ExecuteTest( + "public class TestClass { int a = 123; }\n" + "public class TestClass2 extends TestClass { int b = 456; }\n" + ); + // Note: Use --CBotUT_TestSaveState command line arg. + ExecuteTest( + "extern void TestSaveInheritedMembers()\n" + "{\n" + " TestClass2 t();\n" + " ASSERT(t.a == 123);\n" + " ASSERT(t.b == 456);\n" + " t.a = 789; t.b = 1011;\n" + " ASSERT(t.a == 789);\n" + " ASSERT(t.b == 1011);\n" + " ASSERT(789 == t.a);\n" + " ASSERT(1011 == t.b);\n" + "}\n" + ); +} From 309f80b25f4a20940598e5118b1a98691793a841 Mon Sep 17 00:00:00 2001 From: melex750 Date: Fri, 11 Jun 2021 22:46:23 -0400 Subject: [PATCH 88/98] Fix some bugs and memory leaks in CBOT * Added CBotStack::StackOver() calls where it was possible to go out-of-bounds when calling CBotStack::AddStack(). * Fixed some bugs in CBotExternalCallClass --- src/CBot/CBotDefParam.cpp | 1 + src/CBot/CBotExternalCall.cpp | 39 +++++++++++++------------ src/CBot/CBotInstr/CBotDefClass.cpp | 1 + src/CBot/CBotInstr/CBotFunction.cpp | 2 +- src/CBot/CBotInstr/CBotInstrCall.cpp | 1 + src/CBot/CBotInstr/CBotInstrMethode.cpp | 1 + src/CBot/CBotInstr/CBotNew.cpp | 1 + src/CBot/CBotInstr/CBotTwoOpExpr.cpp | 2 +- src/CBot/CBotProgram.cpp | 7 +++-- src/CBot/CBotProgram.h | 10 ++++--- 10 files changed, 39 insertions(+), 26 deletions(-) diff --git a/src/CBot/CBotDefParam.cpp b/src/CBot/CBotDefParam.cpp index de3fd503..75be07eb 100644 --- a/src/CBot/CBotDefParam.cpp +++ b/src/CBot/CBotDefParam.cpp @@ -137,6 +137,7 @@ bool CBotDefParam::Execute(CBotVar** ppVars, CBotStack* &pj) while ( p != nullptr ) { pile = pile->AddStack(); + if (pile->StackOver()) return pj->Return(pile); if (pile->GetState() == 1) // already done? { if (ppVars != nullptr && ppVars[i] != nullptr) ++i; diff --git a/src/CBot/CBotExternalCall.cpp b/src/CBot/CBotExternalCall.cpp index 8862212b..5b1b4c73 100644 --- a/src/CBot/CBotExternalCall.cpp +++ b/src/CBot/CBotExternalCall.cpp @@ -82,19 +82,23 @@ int CBotExternalCallList::DoCall(CBotToken* token, CBotVar* thisVar, CBotVar** p CBotExternalCall* pt = m_list[token->GetString()].get(); - if (pStack->IsCallFinished()) return true; - CBotStack* pile = pStack->AddStackExternalCall(pt); + if (thisVar == nullptr && pStack->IsCallFinished()) return true; // only for non-method external call - // lists the parameters depending on the contents of the stack (pStackVar) - CBotVar* pVar = MakeListVars(ppVar, true); + // if this is a method call we need to use AddStack() + CBotStack* pile = (thisVar != nullptr) ? pStack->AddStack() : pStack->AddStackExternalCall(pt); - // creates a variable to the result - CBotVar* pResult = rettype.Eq(CBotTypVoid) ? nullptr : CBotVar::Create("", rettype); + if (pile->GetState() == 0) // the first time? + { + // lists the parameters depending on the contents of the stack + CBotVar* pVar = MakeListVars(ppVar, true); + pile->SetVar(pVar); - pile->SetVar(pVar); - - CBotStack* pile2 = pile->AddStack(); - pile2->SetVar(pResult); + CBotStack* pile2 = pile->AddStack(); + // creates a variable to the result + CBotVar* pResult = rettype.Eq(CBotTypVoid) ? nullptr : CBotVar::Create("", rettype); + pile2->SetVar(pResult); + pile->IncState(); // increment state to mark this step done + } pile->SetError(CBotNoErr, token); // save token for the position in case of error return pt->Run(thisVar, pStack); @@ -107,7 +111,8 @@ bool CBotExternalCallList::RestoreCall(CBotToken* token, CBotVar* thisVar, CBotV CBotExternalCall* pt = m_list[token->GetString()].get(); - CBotStack* pile = pStack->RestoreStackEOX(pt); + // if this is a method call we need to use RestoreStack() + CBotStack* pile = (thisVar != nullptr) ? pStack->RestoreStack() : pStack->RestoreStackEOX(pt); if (pile == nullptr) return true; pile->RestoreStack(); @@ -163,8 +168,7 @@ bool CBotExternalCallDefault::Run(CBotVar* thisVar, CBotStack* pStack) return false; } - if (result != nullptr) pStack->SetCopyVar(result); - + pStack->Return(pile2); // return 'result' and clear extra stack return true; } @@ -187,8 +191,8 @@ CBotTypResult CBotExternalCallClass::Compile(CBotVar* thisVar, CBotVar* args, vo bool CBotExternalCallClass::Run(CBotVar* thisVar, CBotStack* pStack) { - if (pStack->IsCallFinished()) return true; - CBotStack* pile = pStack->AddStackExternalCall(this); + assert(thisVar != nullptr); + CBotStack* pile = pStack->AddStack(); CBotVar* args = pile->GetVar(); CBotStack* pile2 = pile->AddStack(); @@ -207,9 +211,8 @@ bool CBotExternalCallClass::Run(CBotVar* thisVar, CBotStack* pStack) return false; } - if (result != nullptr) pStack->SetCopyVar(result); - + pStack->Return(pile2); // return 'result' and clear extra stack return true; } -} +} // namespace CBot diff --git a/src/CBot/CBotInstr/CBotDefClass.cpp b/src/CBot/CBotInstr/CBotDefClass.cpp index c7711703..640b56eb 100644 --- a/src/CBot/CBotInstr/CBotDefClass.cpp +++ b/src/CBot/CBotInstr/CBotDefClass.cpp @@ -360,6 +360,7 @@ bool CBotDefClass::Execute(CBotStack* &pj) if ( p != nullptr) while ( true ) { pile2 = pile2->AddStack(); // place on the stack for the results + if (pile2->StackOver()) return pj->Return(pile2); if ( pile2->GetState() == 0 ) { if (!p->Execute(pile2)) return false; // interrupted here? diff --git a/src/CBot/CBotInstr/CBotFunction.cpp b/src/CBot/CBotInstr/CBotFunction.cpp index 478b9196..e4a62e95 100644 --- a/src/CBot/CBotInstr/CBotFunction.cpp +++ b/src/CBot/CBotInstr/CBotFunction.cpp @@ -445,7 +445,7 @@ bool CBotFunction::Execute(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance) pile->IncState(); } - if ( !m_block->Execute(pile) ) + if (!pile->GetRetVar(m_block->Execute(pile))) { if ( pile->GetError() < 0 ) pile->SetError( CBotNoErr ); diff --git a/src/CBot/CBotInstr/CBotInstrCall.cpp b/src/CBot/CBotInstr/CBotInstrCall.cpp index 60689cb1..b3d151a7 100644 --- a/src/CBot/CBotInstr/CBotInstrCall.cpp +++ b/src/CBot/CBotInstr/CBotInstrCall.cpp @@ -138,6 +138,7 @@ bool CBotInstrCall::Execute(CBotStack* &pj) if ( p != nullptr) while ( true ) { pile = pile->AddStack(); // place on the stack for the results + if (pile->StackOver()) return pj->Return(pile); if ( pile->GetState() == 0 ) { if (!p->Execute(pile)) return false; // interrupted here? diff --git a/src/CBot/CBotInstr/CBotInstrMethode.cpp b/src/CBot/CBotInstr/CBotInstrMethode.cpp index 12c50466..a69ae7c9 100644 --- a/src/CBot/CBotInstr/CBotInstrMethode.cpp +++ b/src/CBot/CBotInstr/CBotInstrMethode.cpp @@ -164,6 +164,7 @@ bool CBotInstrMethode::ExecuteVar(CBotVar* &pVar, CBotStack* &pj, CBotToken* pre } ppVars[i++] = pile2->GetVar(); // construct the list of pointers pile2 = pile2->AddStack(); // space on the stack for the result + if (pile2->StackOver()) return pj->Return(pile2); p = p->GetNext(); if ( p == nullptr) break; } diff --git a/src/CBot/CBotInstr/CBotNew.cpp b/src/CBot/CBotInstr/CBotNew.cpp index 5f7539b1..b97f4e68 100644 --- a/src/CBot/CBotInstr/CBotNew.cpp +++ b/src/CBot/CBotInstr/CBotNew.cpp @@ -189,6 +189,7 @@ bool CBotNew::Execute(CBotStack* &pj) if (p != nullptr) while ( true) { pile2 = pile2->AddStack(); // space on the stack for the result + if (pile2->StackOver()) return pj->Return(pile2); if (pile2->GetState() == 0) { if (!p->Execute(pile2)) return false; // interrupted here? diff --git a/src/CBot/CBotInstr/CBotTwoOpExpr.cpp b/src/CBot/CBotInstr/CBotTwoOpExpr.cpp index a1339724..f57633d5 100644 --- a/src/CBot/CBotInstr/CBotTwoOpExpr.cpp +++ b/src/CBot/CBotInstr/CBotTwoOpExpr.cpp @@ -357,6 +357,7 @@ bool CBotTwoOpExpr::Execute(CBotStack* &pStack) CBotStack* pStk2 = pStk1->AddStack(); // adds an item to the stack // or return in case of recovery + if (pStk2->StackOver()) return pStack->Return(pStk2); // 2nd state, evalute right operand if ( pStk2->GetState() == 0 ) @@ -514,7 +515,6 @@ bool CBotTwoOpExpr::Execute(CBotStack* &pStack) pStk2->SetVar(result); // puts the result on the stack if ( err ) pStk2->SetError(err, &m_token); // and the possible error (division by zero) -// pStk1->Return(pStk2); // releases the stack return pStack->Return(pStk2); // transmits the result } diff --git a/src/CBot/CBotProgram.cpp b/src/CBot/CBotProgram.cpp index 428f1086..c55bf06f 100644 --- a/src/CBot/CBotProgram.cpp +++ b/src/CBot/CBotProgram.cpp @@ -34,7 +34,7 @@ namespace CBot { -CBotExternalCallList* CBotProgram::m_externalCalls = new CBotExternalCallList(); +std::unique_ptr CBotProgram::m_externalCalls; CBotProgram::CBotProgram() { @@ -395,6 +395,8 @@ int CBotProgram::GetVersion() void CBotProgram::Init() { + m_externalCalls.reset(new CBotExternalCallList); + CBotProgram::DefineNum("CBotErrZeroDiv", CBotErrZeroDiv); // division by zero CBotProgram::DefineNum("CBotErrNotInit", CBotErrNotInit); // uninitialized variable CBotProgram::DefineNum("CBotErrBadThrow", CBotErrBadThrow); // throw a negative value @@ -420,9 +422,10 @@ void CBotProgram::Free() CBotToken::ClearDefineNum(); m_externalCalls->Clear(); CBotClass::ClearPublic(); + m_externalCalls.reset(); } -CBotExternalCallList* CBotProgram::GetExternalCalls() +const std::unique_ptr& CBotProgram::GetExternalCalls() { return m_externalCalls; } diff --git a/src/CBot/CBotProgram.h b/src/CBot/CBotProgram.h index 8d7576f2..1ac41450 100644 --- a/src/CBot/CBotProgram.h +++ b/src/CBot/CBotProgram.h @@ -19,11 +19,12 @@ #pragma once -#include "CBot/CBotTypResult.h" #include "CBot/CBotEnums.h" -#include #include +#include +#include +#include namespace CBot { @@ -31,6 +32,7 @@ namespace CBot class CBotFunction; class CBotClass; class CBotStack; +class CBotTypResult; class CBotVar; class CBotExternalCallList; @@ -335,11 +337,11 @@ public: /** * \brief Returns static list of all registered external calls */ - static CBotExternalCallList* GetExternalCalls(); + static const std::unique_ptr& GetExternalCalls(); private: //! All external calls - static CBotExternalCallList* m_externalCalls; + static std::unique_ptr m_externalCalls; //! All user-defined functions std::list m_functions{}; //! The entry point function From a279541198411c29d2255f90c93bba80eb68ff9f Mon Sep 17 00:00:00 2001 From: melex750 Date: Fri, 11 Jun 2021 22:47:33 -0400 Subject: [PATCH 89/98] Make all CBotCStack data members non-static --- src/CBot/CBotCStack.cpp | 177 +++++++++++------------- src/CBot/CBotCStack.h | 25 ++-- src/CBot/CBotClass.cpp | 6 +- src/CBot/CBotDefParam.cpp | 2 +- src/CBot/CBotInstr/CBotDefClass.cpp | 4 +- src/CBot/CBotInstr/CBotInstrCall.cpp | 8 +- src/CBot/CBotInstr/CBotInstrMethode.cpp | 4 +- src/CBot/CBotInstr/CBotInstrUtils.cpp | 4 +- src/CBot/CBotInstr/CBotNew.cpp | 4 +- src/CBot/CBotInstr/CBotSwitch.cpp | 2 +- 10 files changed, 111 insertions(+), 125 deletions(-) diff --git a/src/CBot/CBotCStack.cpp b/src/CBot/CBotCStack.cpp index 5065ddfa..ba48ebcb 100644 --- a/src/CBot/CBotCStack.cpp +++ b/src/CBot/CBotCStack.cpp @@ -31,107 +31,100 @@ namespace CBot { -//////////////////////////////////////////////////////////////////////////////// -CBotProgram* CBotCStack::m_prog = nullptr; // init the static variable -CBotError CBotCStack::m_error = CBotNoErr; -int CBotCStack::m_end = 0; -CBotTypResult CBotCStack::m_retTyp = CBotTypResult(0); +struct CBotCStack::Data +{ + //! The program currently being compiled + CBotProgram* prog = nullptr; + //! The current error state of the compile stack + CBotError error = CBotNoErr; + int errEnd = 0; + //! The return type of the function currently being compiled + CBotTypResult retTyp = CBotTypResult(CBotTypVoid); +}; -//////////////////////////////////////////////////////////////////////////////// CBotCStack::CBotCStack(CBotCStack* ppapa) { - m_next = nullptr; m_prev = ppapa; if (ppapa == nullptr) { - m_error = CBotNoErr; - m_start = 0; - m_end = 0; + m_data = new CBotCStack::Data; + m_errStart = 0; m_bBlock = true; } else { - m_start = ppapa->m_start; + m_data = ppapa->m_data; + m_errStart = ppapa->m_errStart; m_bBlock = false; } - - m_listVar = nullptr; - m_var = nullptr; } //////////////////////////////////////////////////////////////////////////////// CBotCStack::~CBotCStack() { - if (m_next != nullptr) delete m_next; - if (m_prev != nullptr) m_prev->m_next = nullptr; // removes chain - - delete m_var; - delete m_listVar; + if (m_prev == nullptr) delete m_data; } //////////////////////////////////////////////////////////////////////////////// CBotCStack* CBotCStack::TokenStack(CBotToken* pToken, bool bBlock) { - if (m_next != nullptr) return m_next; // include on an existing stack + if (m_next) return m_next.get(); // include on an existing stack - CBotCStack* p = new CBotCStack(this); - m_next = p; // channel element - p->m_bBlock = bBlock; + m_next.reset(new CBotCStack(this)); + m_next->m_bBlock = bBlock; - if (pToken != nullptr) p->SetStartError(pToken->GetStart()); + if (pToken != nullptr) m_next->SetStartError(pToken->GetStart()); - return p; + return m_next.get(); +} + +void CBotCStack::DeleteNext() +{ + m_next.reset(); } -//////////////////////////////////////////////////////////////////////////////// CBotInstr* CBotCStack::Return(CBotInstr* inst, CBotCStack* pfils) { if ( pfils == this ) return inst; - if (m_var != nullptr) delete m_var; // value replaced? - m_var = pfils->m_var; // result transmitted - pfils->m_var = nullptr; // not to destroy the variable + m_var = std::move(pfils->m_var); // result transmitted - if (m_error) + if (m_data->error != CBotNoErr) { - m_start = pfils->m_start; // retrieves the position of the error - m_end = pfils->m_end; + m_errStart = pfils->m_errStart; // retrieves the position of the error } - delete pfils; + m_next.reset(); return inst; } //////////////////////////////////////////////////////////////////////////////// CBotFunction* CBotCStack::ReturnFunc(CBotFunction* inst, CBotCStack* pfils) { - if (m_var != nullptr) delete m_var; // value replaced? - m_var = pfils->m_var; // result transmitted - pfils->m_var = nullptr; // not to destroy the variable + m_var = std::move(pfils->m_var); // result transmitted - if (m_error) + if (m_data->error != CBotNoErr) { - m_start = pfils->m_start; // retrieves the position of the error - m_end = pfils->m_end; + m_errStart = pfils->m_errStart; // retrieves the position of the error } - delete pfils; + m_next.reset(); return inst; } //////////////////////////////////////////////////////////////////////////////// CBotError CBotCStack::GetError(int& start, int& end) { - start = m_start; - end = m_end; - return m_error; + start = m_errStart; + end = m_data->errEnd; + return m_data->error; } //////////////////////////////////////////////////////////////////////////////// CBotError CBotCStack::GetError() { - return m_error; + return m_data->error; } //////////////////////////////////////////////////////////////////////////////// @@ -171,18 +164,13 @@ void CBotCStack::SetType(CBotTypResult& type) CBotVar* CBotCStack::FindVar(CBotToken* &pToken) { CBotCStack* p = this; - std::string name = pToken->GetString(); + const auto& name = pToken->GetString(); while (p != nullptr) { - CBotVar* pp = p->m_listVar; - while ( pp != nullptr) + if (p->m_bBlock) for (auto& var : p->m_listVar) { - if (name == pp->GetName()) - { - return pp; - } - pp = pp->m_next; + if (name == var->GetName()) return var.get(); } p = p->m_prev; } @@ -211,39 +199,39 @@ CBotVar* CBotCStack::CopyVar(CBotToken& Token) //////////////////////////////////////////////////////////////////////////////// bool CBotCStack::IsOk() { - return (m_error == 0); + return (m_data->error == CBotNoErr); } //////////////////////////////////////////////////////////////////////////////// void CBotCStack::SetStartError( int pos ) { - if ( m_error != 0) return; // does not change existing error - m_start = pos; + if (m_data->error != CBotNoErr) return; // does not change existing error + m_errStart = pos; } //////////////////////////////////////////////////////////////////////////////// void CBotCStack::SetError(CBotError n, int pos) { - if ( n!= 0 && m_error != 0) return; // does not change existing error - m_error = n; - m_end = pos; + if (n != CBotNoErr && m_data->error != CBotNoErr) return; // does not change existing error + m_data->error = n; + m_data->errEnd = pos; } //////////////////////////////////////////////////////////////////////////////// void CBotCStack::SetError(CBotError n, CBotToken* p) { - if (m_error) return; // does not change existing error - m_error = n; - m_start = p->GetStart(); - m_end = p->GetEnd(); + if (m_data->error != CBotNoErr) return; // does not change existing error + m_data->error = n; + m_errStart = p->GetStart(); + m_data->errEnd = p->GetEnd(); } //////////////////////////////////////////////////////////////////////////////// void CBotCStack::ResetError(CBotError n, int start, int end) { - m_error = n; - m_start = start; - m_end = end; + m_data->error = n; + m_errStart = start; + m_data->errEnd = end; } //////////////////////////////////////////////////////////////////////////////// @@ -261,48 +249,47 @@ bool CBotCStack::NextToken(CBotToken* &p) //////////////////////////////////////////////////////////////////////////////// void CBotCStack::SetProgram(CBotProgram* p) { - m_prog = p; + m_data->prog = p; } //////////////////////////////////////////////////////////////////////////////// CBotProgram* CBotCStack::GetProgram() { - return m_prog; + return m_data->prog; } //////////////////////////////////////////////////////////////////////////////// void CBotCStack::SetRetType(CBotTypResult& type) { - m_retTyp = type; + m_data->retTyp = type; } //////////////////////////////////////////////////////////////////////////////// CBotTypResult CBotCStack::GetRetType() { - return m_retTyp; + return m_data->retTyp; } //////////////////////////////////////////////////////////////////////////////// void CBotCStack::SetVar( CBotVar* var ) { - if (m_var) delete m_var; // replacement of a variable - m_var = var; + m_var.reset(var); } //////////////////////////////////////////////////////////////////////////////// void CBotCStack::SetCopyVar( CBotVar* var ) { - if (m_var) delete m_var; // replacement of a variable + m_var.reset(); if ( var == nullptr ) return; - m_var = CBotVar::Create("", var->GetTypResult(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC)); + m_var.reset(CBotVar::Create("", var->GetTypResult(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC))); m_var->Copy( var ); } //////////////////////////////////////////////////////////////////////////////// CBotVar* CBotCStack::GetVar() { - return m_var; + return m_var.get(); } //////////////////////////////////////////////////////////////////////////////// @@ -310,15 +297,12 @@ void CBotCStack::AddVar(CBotVar* pVar) { CBotCStack* p = this; - // returns to the father element + // find the level of the current block while (p != nullptr && p->m_bBlock == 0) p = p->m_prev; - if ( p == nullptr ) return; + if (p == nullptr || pVar == nullptr) return; - CBotVar** pp = &p->m_listVar; - while ( *pp != nullptr ) pp = &(*pp)->m_next; - - *pp = pVar; // added after + p->m_listVar.emplace_back(pVar); } //////////////////////////////////////////////////////////////////////////////// @@ -369,19 +353,14 @@ void CBotCStack::CreateMemberVars(CBotClass* pClass, bool setDefined) bool CBotCStack::CheckVarLocal(CBotToken* &pToken) { CBotCStack* p = this; - std::string name = pToken->GetString(); + const auto& name = pToken->GetString(); - while (p != nullptr) + // find the level of the current block + while (p != nullptr && p->m_bBlock == 0) p = p->m_prev; + + if (p != nullptr) for (auto& var : p->m_listVar) { - CBotVar* pp = p->m_listVar; - while ( pp != nullptr) - { - if (name == pp->GetName()) - return true; - pp = pp->m_next; - } - if ( p->m_bBlock ) return false; - p = p->m_prev; + if (name == var->GetName()) return true; } return false; } @@ -392,10 +371,10 @@ CBotTypResult CBotCStack::CompileCall(CBotToken* &p, CBotVar** ppVars, long& nId nIdent = 0; CBotTypResult val(-1); - val = m_prog->GetExternalCalls()->CompileCall(p, nullptr, ppVars, this); + val = GetProgram()->GetExternalCalls()->CompileCall(p, nullptr, ppVars, this); if (val.GetType() < 0) { - val = CBotFunction::CompileCall(p->GetString(), ppVars, nIdent, m_prog); + val = CBotFunction::CompileCall(p->GetString(), ppVars, nIdent, GetProgram()); if ( val.GetType() < 0 ) { // pVar = nullptr; // the error is not on a particular parameter @@ -410,13 +389,13 @@ CBotTypResult CBotCStack::CompileCall(CBotToken* &p, CBotVar** ppVars, long& nId //////////////////////////////////////////////////////////////////////////////// bool CBotCStack::CheckCall(CBotToken* &pToken, CBotDefParam* pParam, const std::string& className) { - std::string name = pToken->GetString(); + const auto& name = pToken->GetString(); - if ( m_prog->GetExternalCalls()->CheckCall(name) ) return true; + if ( GetProgram()->GetExternalCalls()->CheckCall(name) ) return true; - for (CBotFunction* pp : m_prog->GetFunctions()) + for (CBotFunction* pp : GetProgram()->GetFunctions()) { - if ( pToken->GetString() == pp->GetName() ) + if ( name == pp->GetName() ) { // ignore methods for a different class if ( className != pp->GetClassName() ) @@ -429,7 +408,7 @@ bool CBotCStack::CheckCall(CBotToken* &pToken, CBotDefParam* pParam, const std:: for (CBotFunction* pp : CBotFunction::m_publicFunctions) { - if ( pToken->GetString() == pp->GetName() ) + if ( name == pp->GetName() ) { // ignore methods for a different class if ( className != pp->GetClassName() ) @@ -443,4 +422,4 @@ bool CBotCStack::CheckCall(CBotToken* &pToken, CBotDefParam* pParam, const std:: return false; } -} +} // namespace CBot diff --git a/src/CBot/CBotCStack.h b/src/CBot/CBotCStack.h index 983dcf42..adcbee59 100644 --- a/src/CBot/CBotCStack.h +++ b/src/CBot/CBotCStack.h @@ -22,6 +22,9 @@ #include "CBot/CBotVar/CBotVar.h" #include "CBot/CBotProgram.h" +#include +#include + namespace CBot { @@ -157,6 +160,11 @@ public: */ CBotCStack* TokenStack(CBotToken* pToken = nullptr, bool bBlock = false); + /*! + * \brief Deletes all subsequent stack frames created by TokenStack. + */ + void DeleteNext(); + /*! * \brief Return Transmits the result upper. * \param p @@ -269,21 +277,20 @@ public: bool NextToken(CBotToken* &p); private: - CBotCStack* m_next; + std::unique_ptr m_next; CBotCStack* m_prev; - static CBotError m_error; - static int m_end; - int m_start; + int m_errStart = 0; + + struct Data; + + CBotCStack::Data* m_data; //! Result of the operations. - CBotVar* m_var; + std::unique_ptr m_var; //! Is part of a block (variables are local to this block). bool m_bBlock; - CBotVar* m_listVar; - //! List of compiled functions. - static CBotProgram* m_prog; - static CBotTypResult m_retTyp; + std::list> m_listVar; }; } // namespace CBot diff --git a/src/CBot/CBotClass.cpp b/src/CBot/CBotClass.cpp index ccf47104..a7993a9a 100644 --- a/src/CBot/CBotClass.cpp +++ b/src/CBot/CBotClass.cpp @@ -605,8 +605,8 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond) // return a method precompiled in pass 1 CBotCStack* pStk = pStack->TokenStack(nullptr, true); CBotDefParam* params = CBotDefParam::Compile(p, pStk ); - delete pStk; - std::list::iterator pfIter = std::find_if(m_pMethod.begin(), m_pMethod.end(), [&pp, ¶ms](CBotFunction* x) + pStack->DeleteNext(); + auto pfIter = std::find_if(m_pMethod.begin(), m_pMethod.end(), [&pp, ¶ms](CBotFunction* x) { return x->GetName() == pp && x->CheckParam( params ); }); @@ -626,7 +626,7 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond) f->m_pProg = pStack->GetProgram(); f->m_bSynchro = bSynchro; } - pStack->Return(nullptr, pile); + pStack->DeleteNext(); } return pStack->IsOk(); diff --git a/src/CBot/CBotDefParam.cpp b/src/CBot/CBotDefParam.cpp index 75be07eb..d25f9bda 100644 --- a/src/CBot/CBotDefParam.cpp +++ b/src/CBot/CBotDefParam.cpp @@ -94,7 +94,7 @@ CBotDefParam* CBotDefParam::Compile(CBotToken* &p, CBotCStack* pStack) prevHasDefault = true; } else pStack->SetError(CBotErrNoExpression, p); - delete pStk; + pStack->DeleteNext(); } else if (prevHasDefault) pStack->SetError(CBotErrDefaultValue, p->GetPrev()); diff --git a/src/CBot/CBotInstr/CBotDefClass.cpp b/src/CBot/CBotInstr/CBotDefClass.cpp index 640b56eb..f50196ed 100644 --- a/src/CBot/CBotInstr/CBotDefClass.cpp +++ b/src/CBot/CBotInstr/CBotDefClass.cpp @@ -135,7 +135,7 @@ CBotInstr* CBotDefClass::Compile(CBotToken* &p, CBotCStack* pStack, CBotClass* p // the constructor is there? // std::string noname; CBotTypResult r = pClass->CompileMethode(&token, var, ppVars, pStk, inst->m_nMethodeIdent); - delete pStk->TokenStack(); // releases the supplement stack + pStk->DeleteNext(); // releases the supplement stack int typ = r.GetType(); if (typ == CBotErrUndefCall) @@ -160,7 +160,7 @@ CBotInstr* CBotDefClass::Compile(CBotToken* &p, CBotCStack* pStack, CBotClass* p if (nullptr != (inst->m_exprRetVar = CBotExprRetVar::Compile(p, pStk, true))) { inst->m_exprRetVar->SetToken(vartoken); - delete pStk->TokenStack(); + pStk->DeleteNext(); } pStk->SetVar(nullptr); diff --git a/src/CBot/CBotInstr/CBotInstrCall.cpp b/src/CBot/CBotInstr/CBotInstrCall.cpp index b3d151a7..2274f3ac 100644 --- a/src/CBot/CBotInstr/CBotInstrCall.cpp +++ b/src/CBot/CBotInstr/CBotInstrCall.cpp @@ -78,12 +78,12 @@ CBotInstr* CBotInstrCall::Compile(CBotToken* &p, CBotCStack* pStack) { // if (pVar2!=nullptr) pp = pVar2->RetToken(); pStack->SetError( static_cast(inst->m_typRes.GetType()), pp ); - delete pStack->TokenStack(); + pStack->DeleteNext(); delete inst; return nullptr; } - delete pStack->TokenStack(); + pStack->DeleteNext(); if ( inst->m_typRes.GetType() > 0 ) { CBotVar* pRes = CBotVar::Create("", inst->m_typRes); @@ -94,7 +94,7 @@ CBotInstr* CBotInstrCall::Compile(CBotToken* &p, CBotCStack* pStack) if (nullptr != (inst->m_exprRetVar = CBotExprRetVar::Compile(p, pStack))) { inst->m_exprRetVar->SetToken(&inst->m_token); - delete pStack->TokenStack(); + pStack->DeleteNext(); } if ( !pStack->IsOk() ) { @@ -105,7 +105,7 @@ CBotInstr* CBotInstrCall::Compile(CBotToken* &p, CBotCStack* pStack) return inst; } p = pp; - delete pStack->TokenStack(); + pStack->DeleteNext(); return nullptr; } diff --git a/src/CBot/CBotInstr/CBotInstrMethode.cpp b/src/CBot/CBotInstr/CBotInstrMethode.cpp index a69ae7c9..6b7045e3 100644 --- a/src/CBot/CBotInstr/CBotInstrMethode.cpp +++ b/src/CBot/CBotInstr/CBotInstrMethode.cpp @@ -70,7 +70,7 @@ CBotInstr* CBotInstrMethode::Compile(CBotToken* &p, CBotCStack* pStack, CBotVar* CBotClass* pClass = var->GetClass(); // pointer to the class inst->m_className = pClass->GetName(); // name of the class CBotTypResult r = pClass->CompileMethode(pp, var, ppVars, pStack, inst->m_MethodeIdent); - delete pStack->TokenStack(); // release parameters on the stack + pStack->DeleteNext(); // release parameters on the stack inst->m_typRes = r; if (inst->m_typRes.GetType() > 20) @@ -95,7 +95,7 @@ CBotInstr* CBotInstrMethode::Compile(CBotToken* &p, CBotCStack* pStack, CBotVar* if (nullptr != (inst->m_exprRetVar = CBotExprRetVar::Compile(p, pStack, bMethodChain))) { inst->m_exprRetVar->SetToken(pp); - delete pStack->TokenStack(); + pStack->DeleteNext(); } if ( pStack->IsOk() ) diff --git a/src/CBot/CBotInstr/CBotInstrUtils.cpp b/src/CBot/CBotInstr/CBotInstrUtils.cpp index 0b56267c..c4638d60 100644 --- a/src/CBot/CBotInstr/CBotInstrUtils.cpp +++ b/src/CBot/CBotInstr/CBotInstrUtils.cpp @@ -65,7 +65,7 @@ CBotInstr* CompileParams(CBotToken* &p, CBotCStack* pStack, CBotVar** ppVars) { if (pile->GetTypResult().Eq(99)) { - delete pStack->TokenStack(); + pStack->DeleteNext(); pStack->SetError(CBotErrVoid, p->GetStart()); return nullptr; } @@ -78,7 +78,7 @@ CBotInstr* CompileParams(CBotToken* &p, CBotCStack* pStack, CBotVar** ppVars) } pStack->SetError(CBotErrClosePar, p->GetStart()); - delete pStack->TokenStack(); + pStack->DeleteNext(); return nullptr; } } diff --git a/src/CBot/CBotInstr/CBotNew.cpp b/src/CBot/CBotInstr/CBotNew.cpp index b97f4e68..dd8d04ac 100644 --- a/src/CBot/CBotInstr/CBotNew.cpp +++ b/src/CBot/CBotInstr/CBotNew.cpp @@ -87,7 +87,7 @@ CBotInstr* CBotNew::Compile(CBotToken* &p, CBotCStack* pStack) // constructor exist? CBotTypResult r = pClass->CompileMethode(&inst->m_vartoken, pVar, ppVars, pStk, inst->m_nMethodeIdent); - delete pStk->TokenStack(); // release extra stack + pStk->DeleteNext(); // release extra stack int typ = r.GetType(); // if there is no constructor, and no parameters either, it's ok @@ -115,7 +115,7 @@ CBotInstr* CBotNew::Compile(CBotToken* &p, CBotCStack* pStack) if (nullptr != (inst->m_exprRetVar = CBotExprRetVar::Compile(p, pStk, true))) { inst->m_exprRetVar->SetToken(pp); - delete pStk->TokenStack(); + pStk->DeleteNext(); } if (pStack->IsOk()) diff --git a/src/CBot/CBotInstr/CBotSwitch.cpp b/src/CBot/CBotInstr/CBotSwitch.cpp index 9436407b..c75e9aa1 100644 --- a/src/CBot/CBotInstr/CBotSwitch.cpp +++ b/src/CBot/CBotInstr/CBotSwitch.cpp @@ -71,7 +71,7 @@ CBotInstr* CBotSwitch::Compile(CBotToken* &p, CBotCStack* pStack) { if ( p->GetType() == ID_CASE || p->GetType() == ID_DEFAULT) { - delete pStk2; + pStk->DeleteNext(); pStk2 = pStk->TokenStack(p, true); // some space for a stack, plz caseInst = static_cast(CBotCase::Compile(p, pStk2, inst->m_labels)); From 27466a42238e5ac31c5a57131e135796f4041d35 Mon Sep 17 00:00:00 2001 From: melex750 Date: Fri, 11 Jun 2021 22:48:50 -0400 Subject: [PATCH 90/98] Make all CBotStack data members non-static --- src/CBot/CBotProgram.cpp | 7 -- src/CBot/CBotProgram.h | 8 -- src/CBot/CBotStack.cpp | 138 ++++++++++++++++++------------ src/CBot/CBotStack.h | 31 +++---- src/CBot/CBotVar/CBotVarClass.cpp | 11 +-- src/script/scriptfunc.cpp | 1 - 6 files changed, 92 insertions(+), 104 deletions(-) diff --git a/src/CBot/CBotProgram.cpp b/src/CBot/CBotProgram.cpp index c55bf06f..4a09eef2 100644 --- a/src/CBot/CBotProgram.cpp +++ b/src/CBot/CBotProgram.cpp @@ -243,13 +243,6 @@ CBotVar* CBotProgram::GetStackVars(std::string& functionName, int level) return m_stack->GetStackVars(functionName, level); } -//////////////////////////////////////////////////////////////////////////////// -void CBotProgram::SetTimer(int n) -{ - CBotStack::SetTimer( n ); -} - -//////////////////////////////////////////////////////////////////////////////// CBotError CBotProgram::GetError() { return m_error; diff --git a/src/CBot/CBotProgram.h b/src/CBot/CBotProgram.h index 1ac41450..41ef6b8b 100644 --- a/src/CBot/CBotProgram.h +++ b/src/CBot/CBotProgram.h @@ -202,14 +202,6 @@ public: */ void Stop(); - /** - * \brief Sets the number of steps (parts of instructions) to execute in Run() before suspending the program execution - * \param n new timer value - * - * FIXME: Seems to be currently kind of broken (see issue #410) - */ - static void SetTimer(int n); - /** * \brief Add a function that can be called from CBot * diff --git a/src/CBot/CBotStack.cpp b/src/CBot/CBotStack.cpp index 25e895d7..7de0670b 100644 --- a/src/CBot/CBotStack.cpp +++ b/src/CBot/CBotStack.cpp @@ -39,16 +39,24 @@ namespace CBot const int DEFAULT_TIMER = 100; -int CBotStack::m_initimer = DEFAULT_TIMER; -int CBotStack::m_timer = 0; -CBotVar* CBotStack::m_retvar = nullptr; -CBotError CBotStack::m_error = CBotNoErr; -int CBotStack::m_start = 0; -int CBotStack::m_end = 0; -std::string CBotStack::m_labelBreak=""; -void* CBotStack::m_pUser = nullptr; +struct CBotStack::Data +{ + int initimer = DEFAULT_TIMER; + int timer = 0; + + CBotError error = CBotNoErr; + int errStart = 0; + int errEnd = 0; + + std::string labelBreak = ""; + + CBotProgram* baseProg = nullptr; + CBotStack* topStack = nullptr; + void* pUser = nullptr; + + std::unique_ptr retvar; +}; -//////////////////////////////////////////////////////////////////////////////// CBotStack* CBotStack::AllocateStack() { CBotStack* p; @@ -73,7 +81,8 @@ CBotStack* CBotStack::AllocateStack() pp ++; } - m_error = CBotNoErr; // avoids deadlocks because m_error is static + p->m_data = new CBotStack::Data; + p->m_data->topStack = p; return p; } @@ -97,6 +106,7 @@ void CBotStack::Delete() CBotStack* p = m_prev; bool bOver = m_bOver; + if ( m_prev == nullptr ) delete m_data; // clears the freed block memset(this, 0, sizeof(CBotStack)); @@ -123,6 +133,7 @@ CBotStack* CBotStack::AddStack(CBotInstr* instr, BlockVisibilityType bBlock) while ( p->m_prev != nullptr ); m_next = p; // chain an element + p->m_data = m_data; p->m_block = bBlock; p->m_instr = instr; p->m_prog = m_prog; @@ -166,6 +177,7 @@ CBotStack* CBotStack::AddStack2(BlockVisibilityType bBlock) while ( p->m_prev != nullptr ); m_next2 = p; // chain an element + p->m_data = m_data; p->m_prev = this; p->m_block = bBlock; p->m_prog = m_prog; @@ -220,18 +232,32 @@ bool CBotStack::ReturnKeep(CBotStack* pfils) bool CBotStack::StackOver() { if (!m_bOver) return false; - m_error = CBotErrStackOver; + m_data->error = CBotErrStackOver; return true; } -//////////////////////////////////////////////////////////////////////////////// +CBotError CBotStack::GetError(int& start, int& end) +{ + start = m_data->errStart; + end = m_data->errEnd; + return m_data->error; +} + +CBotError CBotStack::GetError() +{ + return m_data->error; +} + +bool CBotStack::IsOk() +{ + return m_data->error == CBotNoErr; +} + void CBotStack::Reset() { - m_timer = m_initimer; // resets the timer - m_error = CBotNoErr; -// m_start = 0; -// m_end = 0; - m_labelBreak.clear(); + m_data->timer = m_data->initimer; // resets the timer + m_data->error = CBotNoErr; + m_data->labelBreak.clear(); } //////////////////////////////////////////////////////////////////////////////// @@ -258,35 +284,35 @@ CBotStack* CBotStack::RestoreStackEOX(CBotExternalCall* instr) // routine for execution step by step bool CBotStack::IfStep() { - if ( m_initimer > 0 || m_step++ > 0 ) return false; + if (m_data->initimer > 0 || m_step++ > 0) return false; return true; } //////////////////////////////////////////////////////////////////////////////// bool CBotStack::BreakReturn(CBotStack* pfils, const std::string& name) { - if ( m_error>=0 ) return false; // normal output - if ( m_error==CBotError(-3) ) return false; // normal output (return current) + if (m_data->error >= CBotNoErr) return false; // normal output + if (m_data->error == CBotError(-3)) return false; // normal output (return current) - if (!m_labelBreak.empty() && (name.empty() || m_labelBreak != name)) + if (!m_data->labelBreak.empty() && (name.empty() || m_data->labelBreak != name)) return false; // it's not for me - m_error = CBotNoErr; - m_labelBreak.clear(); + m_data->error = CBotNoErr; + m_data->labelBreak.clear(); return Return(pfils); } //////////////////////////////////////////////////////////////////////////////// bool CBotStack::IfContinue(int state, const std::string& name) { - if ( m_error != CBotError(-2) ) return false; + if (m_data->error != CBotError(-2)) return false; - if (!m_labelBreak.empty() && (name.empty() || m_labelBreak != name)) + if (!m_data->labelBreak.empty() && (name.empty() || m_data->labelBreak != name)) return false; // it's not for me m_state = state; // where again? - m_error = CBotNoErr; - m_labelBreak.clear(); + m_data->error = CBotNoErr; + m_data->labelBreak.clear(); if (m_next != nullptr) m_next->Delete(); // purge above stack return true; } @@ -294,11 +320,11 @@ bool CBotStack::IfContinue(int state, const std::string& name) //////////////////////////////////////////////////////////////////////////////// void CBotStack::SetBreak(int val, const std::string& name) { - m_error = static_cast(-val); // reacts as an Exception - m_labelBreak = name; + m_data->error = static_cast(-val); // reacts as an Exception + m_data->labelBreak = name; if (val == 3) // for a return { - m_retvar = m_var; + m_data->retvar.reset(m_var); m_var = nullptr; } } @@ -307,12 +333,11 @@ void CBotStack::SetBreak(int val, const std::string& name) //////////////////////////////////////////////////////////////////////////////// bool CBotStack::GetRetVar(bool bRet) { - if (m_error == CBotError(-3)) + if (m_data->error == CBotError(-3)) { if ( m_var ) delete m_var; - m_var = m_retvar; - m_retvar = nullptr; - m_error = CBotNoErr; + m_var = m_data->retvar.release(); + m_data->error = CBotNoErr; return true; } return bRet; // interrupted by something other than return @@ -322,7 +347,7 @@ bool CBotStack::GetRetVar(bool bRet) CBotVar* CBotStack::FindVar(CBotToken*& pToken, bool bUpdate) { CBotStack* p = this; - std::string name = pToken->GetString(); + const auto& name = pToken->GetString(); while (p != nullptr) { @@ -332,7 +357,7 @@ CBotVar* CBotStack::FindVar(CBotToken*& pToken, bool bUpdate) if (pp->GetName() == name) { if ( bUpdate ) - pp->Update(m_pUser); + pp->Update(m_data->pUser); return pp; } @@ -375,7 +400,7 @@ CBotVar* CBotStack::FindVar(long ident, bool bUpdate) if (pp->GetUniqNum() == ident) { if ( bUpdate ) - pp->Update(m_pUser); + pp->Update(m_data->pUser); return pp; } @@ -410,8 +435,8 @@ bool CBotStack::SetState(int n, int limite) { m_state = n; - m_timer--; // decrement the timer - return ( m_timer > limite ); // interrupted if timer pass + m_data->timer--; // decrement the timer + return (m_data->timer > limite); // interrupted if timer pass } //////////////////////////////////////////////////////////////////////////////// @@ -419,46 +444,46 @@ bool CBotStack::IncState(int limite) { m_state++; - m_timer--; // decrement the timer - return ( m_timer > limite ); // interrupted if timer pass + m_data->timer--; // decrement the timer + return (m_data->timer > limite); // interrupted if timer pass } //////////////////////////////////////////////////////////////////////////////// void CBotStack::SetError(CBotError n, CBotToken* token) { - if (n != CBotNoErr && m_error != CBotNoErr) return; // does not change existing error - m_error = n; + if (n != CBotNoErr && m_data->error != CBotNoErr) return; // does not change existing error + m_data->error = n; if (token != nullptr) { - m_start = token->GetStart(); - m_end = token->GetEnd(); + m_data->errStart = token->GetStart(); + m_data->errEnd = token->GetEnd(); } } //////////////////////////////////////////////////////////////////////////////// void CBotStack::ResetError(CBotError n, int start, int end) { - m_error = n; - m_start = start; - m_end = end; + m_data->error = n; + m_data->errStart = start; + m_data->errEnd = end; } //////////////////////////////////////////////////////////////////////////////// void CBotStack::SetPosError(CBotToken* token) { - m_start = token->GetStart(); - m_end = token->GetEnd(); + m_data->errStart = token->GetStart(); + m_data->errEnd = token->GetEnd(); } //////////////////////////////////////////////////////////////////////////////// void CBotStack::SetTimer(int n) { - m_initimer = n; + m_data->initimer = n; } int CBotStack::GetTimer() { - return m_initimer; + return m_data->initimer; } //////////////////////////////////////////////////////////////////////////////// @@ -542,26 +567,25 @@ void CBotStack::SetProgram(CBotProgram* p) { m_prog = p; m_func = IsFunction::YES; + if (this == m_data->topStack) m_data->baseProg = p; } //////////////////////////////////////////////////////////////////////////////// CBotProgram* CBotStack::GetProgram(bool bFirst) { if ( ! bFirst ) return m_prog; - CBotStack* p = this; - while ( p->m_prev != nullptr ) p = p->m_prev; - return p->m_prog; + return m_data->baseProg; } //////////////////////////////////////////////////////////////////////////////// void* CBotStack::GetUserPtr() { - return m_pUser; + return m_data->pUser; } void CBotStack::SetUserPtr(void* user) { - m_pUser = user; + m_data->pUser = user; } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/CBot/CBotStack.h b/src/CBot/CBotStack.h index 20e8118d..64a81124 100644 --- a/src/CBot/CBotStack.h +++ b/src/CBot/CBotStack.h @@ -82,9 +82,6 @@ public: //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** \name Error management - * - * BE CAREFUL - errors are stored in static variables! - * \todo Refactor that */ //@{ @@ -94,24 +91,21 @@ public: * \param[out] end Ending position in code of the error * \return Error number */ - CBotError GetError(int& start, int& end) { start = m_start; end = m_end; return m_error; } + CBotError GetError(int& start, int& end); /** * \brief Get last error * \return Error number * \see GetError(int&, int&) for error position in code */ - CBotError GetError() { return m_error; } + CBotError GetError(); /** * \brief Check if there was an error * \return false if an error occurred * \see GetError() */ - bool IsOk() - { - return m_error == CBotNoErr; - } + bool IsOk(); /** * \brief Set execution error unless it's already set unless you are trying to reset it @@ -357,7 +351,7 @@ public: /** * \todo Document * - * Copies the result value from static m_retvar (m_var at a moment of SetBreak(3)) to this stack result + * Copies the result value from m_data->retvar (m_var at a moment of SetBreak(3)) to this stack result */ bool GetRetVar(bool bRet); @@ -446,11 +440,11 @@ public: * * \todo Full documentation of the timer */ - static void SetTimer(int n); + void SetTimer(int n); /** * \brief Get the current configured maximum number of "timer ticks" (parts of instructions) to execute */ - static int GetTimer(); + int GetTimer(); /** * \brief Get current position in the program @@ -476,10 +470,10 @@ private: int m_state; int m_step; - static CBotError m_error; - static int m_start; - static int m_end; - static CBotVar* m_retvar; // result of a return + + struct Data; + + CBotStack::Data* m_data; CBotVar* m_var; // result of the operations CBotVar* m_listVar; // variables declared at this level @@ -489,11 +483,6 @@ private: //! CBotProgram instance the execution is in in this stack level CBotProgram* m_prog; - static int m_initimer; - static int m_timer; - static std::string m_labelBreak; - static void* m_pUser; - //! The corresponding instruction CBotInstr* m_instr; //! If this stack level holds a function call diff --git a/src/CBot/CBotVar/CBotVarClass.cpp b/src/CBot/CBotVar/CBotVarClass.cpp index 0e14e077..3ee19874 100644 --- a/src/CBot/CBotVar/CBotVarClass.cpp +++ b/src/CBot/CBotVar/CBotVarClass.cpp @@ -380,14 +380,7 @@ void CBotVarClass::DecrementUse() { m_CptUse++; // does not return to the destructor - // m_error is static in the stack - // saves the value for return - CBotError err; - int start, end; - CBotStack* pile = nullptr; - err = pile->GetError(start,end); // stack == nullptr it does not bother! - - pile = CBotStack::AllocateStack(); // clears the error + CBotStack* pile = CBotStack::AllocateStack(); CBotVar* ppVars[1]; ppVars[0] = nullptr; @@ -401,8 +394,6 @@ void CBotVarClass::DecrementUse() while ( pile->IsOk() && !m_pClass->ExecuteMethode(ident, pThis, ppVars, CBotTypResult(CBotTypVoid), pile, &token)) ; // waits for the end - pile->ResetError(err, start,end); - pile->Delete(); delete pThis; m_CptUse--; diff --git a/src/script/scriptfunc.cpp b/src/script/scriptfunc.cpp index ad1a3839..f35c7a2f 100644 --- a/src/script/scriptfunc.cpp +++ b/src/script/scriptfunc.cpp @@ -3411,7 +3411,6 @@ private: void CScriptFunctions::Init() { - CBotProgram::SetTimer(100); CBotProgram::Init(); for (int i = 0; i < OBJECT_MAX; i++) From 9f5ee21bbef5e1095fa235cdf9e0e9a7ed70e8bb Mon Sep 17 00:00:00 2001 From: melex750 Date: Fri, 11 Jun 2021 23:28:53 -0400 Subject: [PATCH 91/98] Restore repeat(n) instruction fixes #1403 --- src/CBot/CBotEnums.h | 1 + src/CBot/CBotInstr/CBotInstr.cpp | 6 +- src/CBot/CBotInstr/CBotRepeat.cpp | 165 ++++++++++++++++++++++++++++++ src/CBot/CBotInstr/CBotRepeat.h | 62 +++++++++++ src/CBot/CBotToken.cpp | 1 + src/CBot/CMakeLists.txt | 2 + src/script/cbottoken.cpp | 2 + test/unit/CBot/CBot_test.cpp | 65 ++++++++++++ 8 files changed, 303 insertions(+), 1 deletion(-) create mode 100644 src/CBot/CBotInstr/CBotRepeat.cpp create mode 100644 src/CBot/CBotInstr/CBotRepeat.h diff --git a/src/CBot/CBotEnums.h b/src/CBot/CBotEnums.h index 9ed38000..963ca261 100644 --- a/src/CBot/CBotEnums.h +++ b/src/CBot/CBotEnums.h @@ -100,6 +100,7 @@ enum TokenId ID_STATIC, ID_PROTECTED, ID_PRIVATE, + ID_REPEAT, ID_INT, ID_FLOAT, ID_BOOLEAN, diff --git a/src/CBot/CBotInstr/CBotInstr.cpp b/src/CBot/CBotInstr/CBotInstr.cpp index b6fbbc66..0115ba28 100644 --- a/src/CBot/CBotInstr/CBotInstr.cpp +++ b/src/CBot/CBotInstr/CBotInstr.cpp @@ -30,6 +30,7 @@ #include "CBot/CBotInstr/CBotExpression.h" #include "CBot/CBotInstr/CBotFor.h" #include "CBot/CBotInstr/CBotIf.h" +#include "CBot/CBotInstr/CBotRepeat.h" #include "CBot/CBotInstr/CBotReturn.h" #include "CBot/CBotInstr/CBotSwitch.h" #include "CBot/CBotInstr/CBotThrow.h" @@ -176,7 +177,7 @@ CBotInstr* CBotInstr::Compile(CBotToken* &p, CBotCStack* pStack) { type = pp->GetType(); // Allow only instructions that accept a label - if (!IsOfTypeList(pp, ID_WHILE, ID_FOR, ID_DO, 0)) + if (!IsOfTypeList(pp, ID_WHILE, ID_FOR, ID_DO, ID_REPEAT, 0)) { pStack->SetError(CBotErrLabel, pp->GetStart()); return nullptr; @@ -195,6 +196,9 @@ CBotInstr* CBotInstr::Compile(CBotToken* &p, CBotCStack* pStack) case ID_DO: return CBotDo::Compile(p, pStack); + case ID_REPEAT: + return CBotRepeat::Compile(p, pStack); + case ID_BREAK: case ID_CONTINUE: return CBotBreak::Compile(p, pStack); diff --git a/src/CBot/CBotInstr/CBotRepeat.cpp b/src/CBot/CBotInstr/CBotRepeat.cpp new file mode 100644 index 00000000..8d8e0553 --- /dev/null +++ b/src/CBot/CBotInstr/CBotRepeat.cpp @@ -0,0 +1,165 @@ +/* + * This file is part of the Colobot: Gold Edition source code + * Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam + * http://epsitec.ch; http://colobot.info; http://github.com/colobot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#include "CBot/CBotInstr/CBotRepeat.h" + +#include "CBot/CBotInstr/CBotBlock.h" +#include "CBot/CBotInstr/CBotExpression.h" + +#include "CBot/CBotCStack.h" +#include "CBot/CBotStack.h" + +namespace CBot +{ + +CBotRepeat::CBotRepeat() +{ + m_expr = nullptr; + m_block = nullptr; +} + +CBotRepeat::~CBotRepeat() +{ + delete m_expr; + delete m_block; +} + +CBotInstr* CBotRepeat::Compile(CBotToken* &p, CBotCStack* pStack) +{ + CBotRepeat* inst = new CBotRepeat(); // creates the object + CBotToken* pp = p; // preserves at the ^ token (starting position) + + if ( IsOfType( p, TokenTypVar ) && IsOfType( p, ID_DOTS ) ) + inst->m_label = pp->GetString(); // register the name of label + + inst->SetToken(p); + if (!IsOfType(p, ID_REPEAT)) return nullptr; // should never happen + + CBotCStack* pStk = pStack->TokenStack(pp); + + if ( IsOfType(p, ID_OPENPAR ) ) + { + CBotToken* ppp = p; // preserves the ^ token (starting position) + if ( nullptr != (inst->m_expr = CBotExpression::Compile( p, pStk )) ) + { + if ( pStk->GetType() < CBotTypLong ) + { + if ( IsOfType(p, ID_CLOSEPAR ) ) + { + IncLvl(inst->m_label); + inst->m_block = CBotBlock::CompileBlkOrInst( p, pStk, true ); + DecLvl(); + + if ( pStk->IsOk() ) // the statement block is ok (it may be empty!) + return pStack->Return(inst, pStk); + } + pStack->SetError(CBotErrClosePar, p->GetStart()); + } + pStk->SetStartError(ppp->GetStart()); + pStk->SetError(CBotErrBadType1, p->GetStart()); + } + pStack->SetError(CBotErrBadNum, p); + } + pStack->SetError(CBotErrOpenPar, p->GetStart()); + + delete inst; + return pStack->Return(nullptr, pStk); +} + +// execution of intruction "repeat" + +bool CBotRepeat::Execute(CBotStack* &pj) +{ + CBotStack* pile = pj->AddStack(this); // adds an item to the stack + // or find in case of recovery + if ( pile->IfStep() ) return false; + + while( true ) switch( pile->GetState() ) // executes the loop + { // there are two possible states (depending on recovery) + case 0: + // evaluates the number of iterations + if ( !m_expr->Execute(pile) ) return false; // interrupted here ? + + // the result of the condition is on the stack + + // terminates if an error or if the condition is false + int n; + if ( !pile->IsOk() || ( n = pile->GetVal() ) < 1 ) + return pj->Return(pile); // releases the stack + + // puts the number of iterations +1 to the "state" + + if (!pile->SetState(n+1)) return false; // ready for further + continue; // continue as a result + + case 1: + // normal end of the loop + return pj->Return(pile); // releases the stack + + default: + // evaluates the associated statement block + if ( m_block != nullptr && !m_block->Execute(pile) ) + { + if (pile->IfContinue(pile->GetState()-1, m_label)) continue; // if continued, will return to test + return pj->BreakReturn(pile, m_label); // releases the stack + } + + // terminates if there is an error + if (!pile->IsOk()) return pj->Return(pile); // releases the stack + + // returns to the test again + if (!pile->SetState(pile->GetState()-1, 0)) return false; + continue; + } +} + +void CBotRepeat::RestoreState(CBotStack* &pj, bool bMain) +{ + if ( !bMain ) return; + CBotStack* pile = pj->RestoreStack(this); // adds an item to the stack + if ( pile == nullptr ) return; + + switch( pile->GetState() ) + { // there are two possible states (depending on recovery) + case 0: + // evaluates the condition + m_expr->RestoreState(pile, bMain); + return; + + case 1: + // evaluates the associated statement block + if ( m_block != nullptr ) m_block->RestoreState(pile, bMain); + return; + } +} + +std::string CBotRepeat::GetDebugData() +{ + return !m_label.empty() ? "m_label = " + m_label : ""; +} + +std::map CBotRepeat::GetDebugLinks() +{ + auto links = CBotInstr::GetDebugLinks(); + links["m_expr"] = m_expr; + links["m_block"] = m_block; + return links; +} + +} // namespace CBot diff --git a/src/CBot/CBotInstr/CBotRepeat.h b/src/CBot/CBotInstr/CBotRepeat.h new file mode 100644 index 00000000..d60f4a09 --- /dev/null +++ b/src/CBot/CBotInstr/CBotRepeat.h @@ -0,0 +1,62 @@ +/* + * This file is part of the Colobot: Gold Edition source code + * Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam + * http://epsitec.ch; http://colobot.info; http://github.com/colobot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#pragma once + +#include "CBot/CBotInstr/CBotInstr.h" + +namespace CBot +{ + +/** + * \brief The "repeat" loop - repeat (times) { ... } + */ +class CBotRepeat : public CBotInstr +{ +public: + CBotRepeat(); + ~CBotRepeat(); + + /// Static method used for compilation + static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); + + /// Execute + bool Execute(CBotStack* &pj) override; + + /// Restore state + void RestoreState(CBotStack* &pj, bool bMain) override; + +protected: + virtual const std::string GetDebugName() override { return "CBotRepeat"; } + virtual std::string GetDebugData() override; + virtual std::map GetDebugLinks() override; + +private: + /// Number of iterations + CBotInstr* m_expr; + + /// Instructions + CBotInstr* m_block; + + /// Label + std::string m_label; // a label if there is + +}; + +} // namespace CBot diff --git a/src/CBot/CBotToken.cpp b/src/CBot/CBotToken.cpp index 2b98b582..38402d94 100644 --- a/src/CBot/CBotToken.cpp +++ b/src/CBot/CBotToken.cpp @@ -65,6 +65,7 @@ static const boost::bimap KEYWORDS = makeBimap Date: Mon, 16 Aug 2021 18:01:08 +0200 Subject: [PATCH 92/98] Update polish translation (#1407) --- data | 2 +- po/pl.po | 52 ++++++++++++++++++++++++++-------------------------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/data b/data index 87aeb32a..c25693b3 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 87aeb32afbc7e4135a5a3533998a9274d9de30a3 +Subproject commit c25693b325da50f5c7b3bc147522a78e2487e204 diff --git a/po/pl.po b/po/pl.po index 5e3daeae..90e9f65f 100644 --- a/po/pl.po +++ b/po/pl.po @@ -32,7 +32,7 @@ msgid "%s: %d pts" msgstr "%s: %d pkt" msgid "+\\Missions with bonus content and optional challenges" -msgstr "" +msgstr "+\\Misje z dodatkową zawartością i opcjonalnymi wyzwaniami" msgid "..behind" msgstr "..za" @@ -188,7 +188,7 @@ msgid "Bot factory" msgstr "Fabryka robotów" msgid "Build (\\key action;)" -msgstr "" +msgstr "Buduj (\\key action;)" msgid "Build a bot factory" msgstr "Zbuduj fabrykę robotów" @@ -206,7 +206,7 @@ msgid "Build a exchange post" msgstr "Zbuduj stację przekaźnikową" msgid "Build a legged builder" -msgstr "" +msgstr "Zbuduj budowniczego na nogach" msgid "Build a legged grabber" msgstr "Zbuduj transporter na nogach" @@ -254,13 +254,13 @@ msgid "Build a subber" msgstr "Zbuduj robota nurka" msgid "Build a target bot" -msgstr "" +msgstr "Zbuduj robota-cel" msgid "Build a thumper" msgstr "Zbuduj robota uderzacza" msgid "Build a tracked builder" -msgstr "" +msgstr "Zbuduj budowniczego na gąsienicach" msgid "Build a tracked grabber" msgstr "Zbuduj transporter na gąsienicach" @@ -275,10 +275,10 @@ msgid "Build a tracked sniffer" msgstr "Zbuduj szperacz na gąsienicach" msgid "Build a vault" -msgstr "" +msgstr "Zbuduj skrytkę" msgid "Build a wheeled builder" -msgstr "" +msgstr "Zbuduj budowniczego na kołach" msgid "Build a wheeled grabber" msgstr "Zbuduj transporter na kołach" @@ -293,7 +293,7 @@ msgid "Build a wheeled sniffer" msgstr "Zbuduj szperacz na kołach" msgid "Build a winged builder" -msgstr "" +msgstr "Zbuduj latającego budowniczego" msgid "Build a winged grabber" msgstr "Zbuduj transporter latający" @@ -528,7 +528,7 @@ msgid "Drawer bot" msgstr "Robot rysownik" msgid "Duplicate label in switch" -msgstr "" +msgstr "Zduplikowana wartość w instrukcji switch" msgid "Dust\\Dust and dirt on bots and buildings" msgstr "Kurz\\Kurz i bród na robotach i budynkach" @@ -549,7 +549,7 @@ msgid "Egg" msgstr "Jajo" msgid "Empty character constant" -msgstr "" +msgstr "Stała będąca pustym znakiem" msgid "Enable\\Enable the selected mod" msgstr "Włącz\\Włącza zaznaczonego moda" @@ -769,7 +769,7 @@ msgid "Inappropriate object" msgstr "Nieodpowiedni obiekt" msgid "Inappropriate sample" -msgstr "" +msgstr "Nieprawidłowa próbka" msgid "Incorrect index type" msgstr "Nieprawidłowy typ indeksu" @@ -814,7 +814,7 @@ msgid "Internal error - tell the developers" msgstr "Błąd wewnętrzny - powiadom twórców gry" msgid "Invalid universal character name" -msgstr "" +msgstr "Nieprawidłowy znak Unicode" msgid "Invert\\Invert values on this axis" msgstr "Odwróć\\Odwróć wartości na tej osi" @@ -844,7 +844,7 @@ msgid "LOADING" msgstr "WCZYTYWANIE" msgid "Legged builder" -msgstr "" +msgstr "Budowniczy na nogach" msgid "Legged grabber" msgstr "Transporter na nogach" @@ -979,7 +979,7 @@ msgid "New ..." msgstr "Nowy ..." msgid "New Folder" -msgstr "" +msgstr "Nowy folder" msgid "New bot available" msgstr "Dostępny nowy robot" @@ -1147,7 +1147,7 @@ msgid "Original game developed by:" msgstr "Twórcy oryginalnej gry:" msgid "Overwrite existing file?" -msgstr "" +msgstr "Nadpisać istniejący plik?" msgid "Parameters missing" msgstr "Brak wymaganego parametru" @@ -1183,7 +1183,7 @@ msgid "Planets:" msgstr "Planety:" msgid "Plans for builder available" -msgstr "" +msgstr "Dostępne plany robota budowniczego" msgid "Plans for defense tower available" msgstr "Dostępne plany wieży obronnej" @@ -1393,7 +1393,7 @@ msgid "Ruin" msgstr "Ruiny" msgid "Run research program for builder" -msgstr "" +msgstr "Rozpocznij prace badawcze nad robotem budowniczym" msgid "Run research program for defense tower" msgstr "Rozpocznij prace badawcze nad wieżą obronną" @@ -1417,7 +1417,7 @@ msgid "Run research program for shooter" msgstr "Rozpocznij prace badawcze nad działem" msgid "Run research program for target bot" -msgstr "" +msgstr "Rozpocznij prace badawcze nad robotem-celem" msgid "Run research program for thumper" msgstr "Rozpocznij prace badawcze nad robotem uderzaczem" @@ -1450,7 +1450,7 @@ msgid "Save\\Saves the current mission" msgstr "Zapisz\\Zapisuje bieżącą misję" msgid "Select Folder" -msgstr "" +msgstr "Wybierz folder" msgid "Select the astronaut\\Selects the astronaut" msgstr "Zaznacz astronautę\\Zaznacza astronautę" @@ -1519,13 +1519,13 @@ msgid "Sound\\Music and game sound volume" msgstr "Dźwięk\\Głośność muzyki i dźwięków gry" msgid "Space Explorer\\Disables astronaut abilities" -msgstr "" +msgstr "Kosmiczny odkrywca\\Wyłącza umiejętności astronauty" msgid "Space Programmer\\Disables radio-control" -msgstr "" +msgstr "Kosmiczny koder\\Wyłącza zdalną kontrolę" msgid "Space Researcher\\Disables using all previously researched technologies" -msgstr "" +msgstr "Kosmiczny badacz\\Blokuje dostęp do poprzednio wynalezionych technologii" msgid "Spaceship" msgstr "Statek kosmiczny" @@ -1705,7 +1705,7 @@ msgid "Too many parameters" msgstr "Za dużo parametrów" msgid "Tracked builder" -msgstr "" +msgstr "Budowniczy na gąsienicach" msgid "Tracked grabber" msgstr "Transporter na gąsienicach" @@ -1762,7 +1762,7 @@ msgid "Unknown command" msgstr "Nieznane polecenie" msgid "Unknown escape sequence" -msgstr "" +msgstr "Nieznany znak ucieczki" msgid "Unknown function" msgstr "Funkcja nieznana" @@ -1819,7 +1819,7 @@ msgid "Website" msgstr "Strona internetowa" msgid "Wheeled builder" -msgstr "" +msgstr "Budowniczy na kołach" msgid "Wheeled grabber" msgstr "Transporter na kołach" @@ -1834,7 +1834,7 @@ msgid "Wheeled sniffer" msgstr "Szperacz na kołach" msgid "Winged builder" -msgstr "" +msgstr "Budowniczy latający" msgid "Winged grabber" msgstr "Transporter latający" From a5d9bae052086fb07a0b47c7dc13a178fa7fb543 Mon Sep 17 00:00:00 2001 From: Fiftytwo Date: Fri, 20 Aug 2021 17:54:30 +0200 Subject: [PATCH 93/98] Fix missing AmphibiousTrainer in drive_type --- src/object/drive_type.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/object/drive_type.cpp b/src/object/drive_type.cpp index ce85d443..b30f4eb7 100644 --- a/src/object/drive_type.cpp +++ b/src/object/drive_type.cpp @@ -62,6 +62,7 @@ DriveType GetDriveFromObject(ObjectType type) case OBJECT_MOBILErs: return DriveType::Heavy; + case OBJECT_MOBILEst: case OBJECT_MOBILEsa: return DriveType::Amphibious; From ecc23dfb3ee38ec4d7e293b9ea56a03bc64f070e Mon Sep 17 00:00:00 2001 From: MrSimbax Date: Sat, 21 Aug 2021 22:18:52 +0200 Subject: [PATCH 94/98] Update data submodule --- data | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data b/data index c25693b3..74c762b4 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit c25693b325da50f5c7b3bc147522a78e2487e204 +Subproject commit 74c762b47fcac7c073a0afb5c82cf046e7ea42f3 From decab2955546f57748b023ab17f30da84b8c9036 Mon Sep 17 00:00:00 2001 From: MrSimbax Date: Sat, 21 Aug 2021 22:22:01 +0200 Subject: [PATCH 95/98] Remove linter CI jobs They require Ubuntu 16.04 which is no longer supported. --- .github/workflows/lint.yml | 194 ---------------------- .github/workflows/lint_upload_results.yml | 67 -------- 2 files changed, 261 deletions(-) delete mode 100644 .github/workflows/lint.yml delete mode 100644 .github/workflows/lint_upload_results.yml diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml deleted file mode 100644 index 967b4c91..00000000 --- a/.github/workflows/lint.yml +++ /dev/null @@ -1,194 +0,0 @@ -name: Linter - -on: [push, pull_request] - -jobs: - lint: - # it's easiest if it matches the version that was used to build colobot-lint, newer versions don't have llvm-3.6-dev in repo... - runs-on: ubuntu-16.04 - env: - CC: /usr/lib/llvm-3.6/bin/clang - CXX: /usr/lib/llvm-3.6/bin/clang++ - CLANG_PREFIX: /usr/lib/llvm-3.6 - steps: - - name: Download Colobot dependencies - run: sudo apt-get update && sudo apt-get install -y --no-install-recommends build-essential cmake libsdl2-dev libsdl2-image-dev libsdl2-ttf-dev libsndfile1-dev libvorbis-dev libogg-dev libpng-dev libglew-dev libopenal-dev libboost-dev libboost-system-dev libboost-filesystem-dev libboost-regex-dev libphysfs-dev gettext git po4a vorbis-tools librsvg2-bin xmlstarlet - - name: Download colobot-lint dependencies - run: sudo apt-get install -y --no-install-recommends clang-3.6 libtinyxml2.6.2v5 - - run: mkdir -p /tmp/colobot-lint - - name: Download colobot-lint - uses: dawidd6/action-download-artifact@v2 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - repo: colobot/colobot-lint - branch: master - workflow: build.yml - workflow_conclusion: success - name: colobot-lint - path: /tmp/colobot-lint/archive - - name: Unpack colobot-lint - working-directory: /tmp/colobot-lint - run: | - # Workaround for Clang not finding system headers - mkdir ./bin - mv ./archive/build/colobot-lint ./bin/ - chmod +x ./bin/colobot-lint - ln -s ${CLANG_PREFIX}/lib ./lib - # Unpack HtmlReport - tar -zxf ./archive/build/html_report.tar.gz - # Clean up - rm -r ./archive - - uses: actions/checkout@v2 - - name: Create build directory - run: cmake -E make_directory build - - name: Run CMake - working-directory: build - run: cmake -DCOLOBOT_LINT_BUILD=1 -DTESTS=1 -DTOOLS=1 -DCMAKE_EXPORT_COMPILE_COMMANDS=1 .. - - name: Run linter - shell: bash - run: | - set -e +x - WORKSPACE="$GITHUB_WORKSPACE" - COLOBOT_DIR="$WORKSPACE" - COLOBOT_BUILD_DIR="$WORKSPACE/build" - COLOBOT_LINT_REPORT_FILE="$WORKSPACE/build/colobot_lint_report.xml" - - cd "/tmp/colobot-lint" - find "$WORKSPACE" \( -wholename "$COLOBOT_DIR/src/*.cpp" \ - -or -wholename "$COLOBOT_DIR/test/unit/*.cpp" \ - -or -wholename "$COLOBOT_BUILD_DIR/fake_header_sources/src/*.cpp" \ - -or -wholename "$COLOBOT_BUILD_DIR/fake_header_sources/test/unit/*.cpp" \) \ - -exec ./bin/colobot-lint \ - -verbose \ - -output-format xml \ - -output-file "$COLOBOT_LINT_REPORT_FILE" \ - -p "$COLOBOT_BUILD_DIR" \ - -project-local-include-path "$COLOBOT_DIR/src" -project-local-include-path "$COLOBOT_BUILD_DIR/src" \ - -license-template-file "$COLOBOT_DIR/LICENSE-HEADER.txt" \ - {} + - - name: Upload results (XML) - uses: actions/upload-artifact@v2 - with: - name: XML results - path: build/colobot_lint_report.xml - - name: Generate HTML report - shell: bash - run: /tmp/colobot-lint/HtmlReport/generate.py --xml-report "build/colobot_lint_report.xml" --output-dir "build/html_report" - - name: Upload results (HTML) - uses: actions/upload-artifact@v2 - with: - name: HTML results - path: build/html_report - - name: Generate GitHub annotations JSON and process check result - shell: python - run: | - import os - import sys - import json - import xml.etree.ElementTree as ET - - OVERALL_STABLE_RULES=[ - "class naming", - "code block placement", - "compile error", - # "compile warning", - # "enum naming", - # "function naming", - "header file not self-contained", - # "implicit bool cast", - # "include style", - # "inconsistent declaration parameter name", - "license header", - # "naked delete", - # "naked new", - # "old style function", - "old-style null pointer", - # "possible forward declaration", - "undefined function", - # "uninitialized field", - # "uninitialized local variable", - # "unused forward declaration", - # "variable naming", - "whitespace", - ] - - STABLE_RULES_WITHOUT_CBOT=[ - "class naming", - "code block placement", - "compile error", - "compile warning", - # "enum naming", - # "function naming", - "header file not self-contained", - # "implicit bool cast", - "include style", - "inconsistent declaration parameter name", - "license header", - "naked delete", - "naked new", - # "old style function", - "old-style null pointer", - # "possible forward declaration", - "undefined function", - "uninitialized field", - # "uninitialized local variable", - "unused forward declaration", - # "variable naming", - "whitespace", - ] - - def we_care_about(file_name, type): - if 'CBot' in file_name: - return type in OVERALL_STABLE_RULES - else: - return type in STABLE_RULES_WITHOUT_CBOT - - results = ET.parse('build/colobot_lint_report.xml') - annotations = [] - stable_annotations = [] - for error in results.find('errors').findall('error'): - location = error.find('location') - file_name = os.path.relpath(location.get('file'), os.environ['GITHUB_WORKSPACE']) - line_num = int(location.get('line')) - type = error.get('id') - severity = error.get('severity') - msg = error.get('msg') - - gh_severity = 'warning' - if severity == 'error': - gh_severity = 'failure' - elif severity == 'information': - gh_severity = 'notice' - - annotation = { - 'path': file_name, - 'start_line': line_num, - 'end_line': line_num, - 'annotation_level': gh_severity, - 'title': type, - 'message': msg - } - annotations.append(annotation) - - if we_care_about(file_name, type): - # don't send the unstable rules to github at all as there are way too many of them and it would overload the API rate limit - stable_annotations.append(annotation) - print('{}:{}: [{}] {}'.format(file_name, line_num, type, msg)) - - summary = 'colobot-lint found {} issues'.format(len(stable_annotations)) - all_ok = len(stable_annotations) == 0 - print('Conclusion: {}'.format(summary)) - - with open("build/annotations.json", "w") as f: - json.dump(annotations, f, indent=4) - with open("build/stable_annotations.json", "w") as f: - json.dump(stable_annotations, f, indent=4) - sys.exit(0 if all_ok else 1) - - name: Upload results (JSON) - uses: actions/upload-artifact@v2 - with: - name: JSON results - path: | - build/annotations.json - build/stable_annotations.json - if: ${{ always() }} diff --git a/.github/workflows/lint_upload_results.yml b/.github/workflows/lint_upload_results.yml deleted file mode 100644 index 3adb3c54..00000000 --- a/.github/workflows/lint_upload_results.yml +++ /dev/null @@ -1,67 +0,0 @@ -name: Linter upload results - -# Upload linter results after succesful linter run -# This is done in a separate workflow to safely use the read-write GitHub token -# See https://securitylab.github.com/research/github-actions-preventing-pwn-requests - -on: - workflow_run: - workflows: ["Linter"] - types: - - completed - -jobs: - lint_upload: - runs-on: ubuntu-16.04 - steps: - - run: pip install requests - - name: Download linter results - uses: dawidd6/action-download-artifact@v2 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - workflow: lint.yml - run_id: ${{ github.event.workflow_run.id }} - name: JSON results - path: results - - name: Send linter results to GitHub - shell: python - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - RUN_ID: ${{ github.event.workflow_run.id }} - run: | - import os - import json - import requests - - # Load the results from the lint job artifact - with open("results/stable_annotations.json", "r") as f: - annotations = json.load(f) - summary = 'colobot-lint found {} issues'.format(len(annotations)) - - # None of the available actions seem to do what I want, they all do stupid things like adding another check... let's just do it manually - # GitHub also doesn't seem to provide you with the check suite or check run ID, so we have to get it from the action ID via the API - s = requests.Session() - s.headers.update({ - 'Authorization': 'token ' + os.environ['GITHUB_TOKEN'], - 'Accept': 'application/vnd.github.antiope-preview+json' # Annotations are still technically a preview feature of the API - }) - action_run = s.get(os.environ['GITHUB_API_URL'] + "/repos/" + os.environ['GITHUB_REPOSITORY'] + "/actions/runs/" + os.environ['RUN_ID']).json() - check_suite = s.get(action_run['check_suite_url']).json() - check_suite_runs = s.get(check_suite['check_runs_url']).json() - check_run = check_suite_runs['check_runs'][0] # NOTE: This assumes that the 'lint' job is the first one in the workflow. You could find it by name if you really wanted. - - # Annotations have to be sent in batches of 50 - first = True - while first or len(annotations) > 0: - first = False - to_send = annotations[:50] - annotations = annotations[50:] - data = { - 'output': { - 'title': summary, - 'summary': summary, - 'annotations': to_send - } - } - r = s.patch(check_run['url'], json=data) - r.raise_for_status() From 92f574d2ca7ddc2ca454f93f20a038b653f56079 Mon Sep 17 00:00:00 2001 From: MrSimbax Date: Sat, 21 Aug 2021 22:25:40 +0200 Subject: [PATCH 96/98] Remove Ubuntu 16.04 from CI jobs --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 145835bc..b312c8a4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -9,7 +9,7 @@ jobs: strategy: matrix: target_os: [linux] - host_os: [ubuntu-16.04, ubuntu-18.04, ubuntu-20.04] + host_os: [ubuntu-18.04, ubuntu-20.04] container: [''] include: - target_os: windows From faa4eaae20a8b5057407880b4efc008e22e56ca3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Przyby=C5=82?= Date: Sat, 21 Aug 2021 22:57:34 +0200 Subject: [PATCH 97/98] Release 0.2.0-alpha: Bump version --- CMakeLists.txt | 8 ++++---- data | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 90843488..700d37b2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,13 +12,13 @@ project(colobot C CXX) ## set(COLOBOT_VERSION_CODENAME "Gold") set(COLOBOT_VERSION_MAJOR 0) -set(COLOBOT_VERSION_MINOR 1) -set(COLOBOT_VERSION_REVISION 12) +set(COLOBOT_VERSION_MINOR 2) +set(COLOBOT_VERSION_REVISION 0) # Used on official releases -#set(COLOBOT_VERSION_RELEASE_CODENAME "-alpha") +set(COLOBOT_VERSION_RELEASE_CODENAME "-alpha") # Used on unreleased, development builds -set(COLOBOT_VERSION_UNRELEASED "+alpha") +#set(COLOBOT_VERSION_UNRELEASED "+alpha") # Append git characteristics to version if(DEFINED COLOBOT_VERSION_UNRELEASED) diff --git a/data b/data index 74c762b4..0ac8197b 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 74c762b47fcac7c073a0afb5c82cf046e7ea42f3 +Subproject commit 0ac8197b7a8a005c714b7696d36c642cf0e81474 From c039e7e8592b40ebf1f8768ac5d15cf7eabde759 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Przyby=C5=82?= Date: Sat, 21 Aug 2021 22:57:34 +0200 Subject: [PATCH 98/98] Post-release 0.2.0-alpha --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 700d37b2..d9998c51 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,9 +16,9 @@ set(COLOBOT_VERSION_MINOR 2) set(COLOBOT_VERSION_REVISION 0) # Used on official releases -set(COLOBOT_VERSION_RELEASE_CODENAME "-alpha") +#set(COLOBOT_VERSION_RELEASE_CODENAME "-alpha") # Used on unreleased, development builds -#set(COLOBOT_VERSION_UNRELEASED "+alpha") +set(COLOBOT_VERSION_UNRELEASED "+alpha") # Append git characteristics to version if(DEFINED COLOBOT_VERSION_UNRELEASED)